Gostaria de armazenar um mapeamento de string -> string em um objeto TypeScript e impor que todas as chaves sejam mapeadas para strings. Por exemplo:
var stuff = {};
stuff["a"] = "foo"; // okay
stuff["b"] = "bar"; // okay
stuff["c"] = false; // ERROR! bool != string
Existe uma maneira de impor que os valores devem ser cadeias (ou qualquer outro tipo ..)?
typescript
Armentage
fonte
fonte
number
Também é permitido como um tipo de indexaçãotype Keys = 'Acceptable' | 'String' | 'Keys'
como um tipo de indexação (chave)?Aqui, a interface
AgeMap
impõe chaves como seqüências de caracteres e valores como números. A palavra-chavename
pode ser qualquer identificador e deve ser usada para sugerir a sintaxe da sua interface / tipo.Você pode usar uma sintaxe semelhante para impor que um objeto tenha uma chave para cada entrada em um tipo de união:
Obviamente, você também pode fazer deste um tipo genérico!
Atualização 10.10.2018: Confira a resposta de @ dracstaxi abaixo - agora há um tipo interno
Record
que faz a maior parte disso para você.Atualização 1.2.2020: removi completamente as interfaces de mapeamento pré-fabricadas da minha resposta. A resposta de @ dracstaxi os torna totalmente irrelevantes. Se você ainda deseja usá-los, verifique o histórico de edições.
fonte
x = {}; x[1] = 2;
no ChromeObject.keys(x)
retorna ["1"] eJSON.stringify(x)
retorna '{"1": 2}'. Os casos de canto com typeofNumber
(por exemplo, Infinito, NaN, 1e300, 999999999999999999999 etc) são convertidos em chaves de seqüência de caracteres. Também tem cuidado de outros casos de canto para as chaves string comox[''] = 'empty string';
,x['000'] = 'threezeros';
x[undefined] = 'foo'
.Uma atualização rápida: desde o Typescript 2.1, existe um tipo incorporado
Record<T, K>
que age como um dicionário.Um exemplo dos documentos:
Documentação do TypeScript 2.1 em
Record<T, K>
A única desvantagem que vejo ao usar isso
{[key: T]: K}
é que você pode codificar informações úteis sobre o tipo de chave que está usando no lugar de "chave"{[prime: number]: yourType}
.Aqui está um regex que escrevi para ajudar nessas conversões. Isso converterá apenas casos em que o rótulo é "chave". Para converter outros rótulos, basta alterar o primeiro grupo de captura:
Encontrar:
\{\s*\[(key)\s*(+\s*:\s*(\w+)\s*\]\s*:\s*([^\}]+?)\s*;?\s*\}
Substituir:
Record<$2, $3>
fonte
{}
?Record
s (diferentemente, digamos, do JavascriptMap
s) fornecem apenas uma maneira de impor o conteúdo de um objeto literal. Você não podenew Record...
econst blah: Record<string, string>;
irá compilarconst blah;
.Record
s:const isBroken: Record<"hat" | "teapot" | "cup", boolean> = { hat: false, cup: false, teapot: true };
A resposta de @Ryan Cavanaugh é totalmente correta e continua válida. Ainda assim, vale a pena acrescentar que, no outono de 16, quando podemos afirmar que o ES6 é suportado pela maioria das plataformas, quase sempre é melhor seguir o Map sempre que você precisar associar alguns dados a alguma chave.
Quando escrevemos
let a: { [s: string]: string; }
, precisamos lembrar que, depois da compilação do texto datilografado, não existem dados do tipo, eles são usados apenas para compilar. E {[s: string]: string; } será compilado para apenas {}.Dito isto, mesmo se você escrever algo como:
Isso simplesmente não será compilado (mesmo que
target es6
você obtenhaerror TS1023: An index signature parameter type must be 'string' or 'number'.
Portanto, praticamente você está limitado a uma string ou um número como chave potencial, portanto não há muito senso de impor a verificação de tipo aqui, especialmente tendo em mente que quando js tenta acessar a chave pelo número, ele a converte em string.
Portanto, é bastante seguro supor que a melhor prática é usar o Map, mesmo que as chaves sejam string, então eu continuaria com:
fonte
let dict: {[key in TrickyKey]: string} = {}
- ondeTrickyKey
é um tipo literal de string (por exemplo"Foo" | "Bar"
).Map
objetos nativos . Os mapas vêm com sobrecarga adicional de memória e (mais importante) precisam ser instanciados manualmente a partir de qualquer dado armazenado como uma string JSON. Eles geralmente são muito úteis, mas não puramente para obter tipos deles.Definir interface
Aplicar chave para ser uma chave específica da interface Configurações
fonte
Com base na resposta de @ shabunc, isso permitiria impor a chave ou o valor - ou ambos - para qualquer coisa que você queira impor.
Também deve funcionar usando em
enum
vez de umatype
definição.fonte