Ok, então estou atualizando o TypeScript do wj-config (caso o caso real se torne relevante), e uma de suas funções é "expandir" uma chave (um valor de string que é dividido na presença de um separador) em um objeto. Exemplo: Key 'a.b.c'
expande para object { a: b { c: <value here> } }
.
Para uma única chave, criei o seguinte InflateKey
tipo:
export type InflateKey<TKey extends string, TValue, TSep extends string> = TKey extends `${infer Key}${TSep}${infer Rest}` ?
{
[K in Key]: InflateKey<Rest, TValue, TSep>
} :
{
[K in TKey]: TValue;
};
Este tipo funciona como esperado. Ótimo! Agora a próxima tarefa é aceitar um objeto cujas chaves são como a chave descrita acima. Exemplo:
const dic = {
'a.b': 1,
'a.c': 33,
'h.x': true,
'z.y': 'Hi'
};
// Now, through the application of a function, the result will look like:
const result = {
a: {
b: 1,
c: 33
},
h: {
x: true
},
z: {
y: 'Hi'
}
};
Preciso de ajuda para digitar este valor de retorno.
Minha linha de pensamento:
export type InflateDictionary<TDic extends Record<string, any>> = InflateKey<key1 of TDic,...> & ... & InflateKey<keyN of TDic,...>;
O acima, é claro, não é TypeScript válido.
Você já escreveu
InflateKey<K, V, ".">
(presumo que só nos importamos com isso"."
aqui) e quer algo que pareça uma intersecção deInflateKey<K, T[K], ".">
para todas as propriedadesK
emkeyof T
, certo? Se sim, então podemos usar a mesma abordagem básica de Transformar tipo de união em tipo de intersecção .A ideia é que produzamos um tipo em que cada um
InflateKey<K, T[K], ".">
termina em uma posição contravariante (veja Diferença entre Variância, Covariância, Contravariância, Bivariância e Invariância em TypeScript ) como o parâmetro de uma função. E então usamos inferência de tipo condicional para inferir um único tipo para essa posição. A inferência de tipo condicional de múltiplos candidatos em posições contravariantes produz uma interseção (veja a documentação nas notas de lançamento do TypeScript 2.8 ). Então aqui está uma maneira de fazer isso:Nós fazemos um tipo mapeado sobre todas as
string
propriedades com -chave deTDic
(string & keyof TDic
em oposição a apenaskeyof TDic
porqueInflateKey
requer umastring
chave), e colocamos cada umaInflateKey
como um parâmetro de função da propriedade. Então nós inferimos paraRecord<string, (x: infer I) => void>
, inferindo um únicoI
para todo o objeto. E essaI
será a interseção que você quer, então nós a retornamos.Vamos testar:
Parece bom. É o tipo que você queria.
Link do playground para o código