Não entendo por que uma função genérica obtém o tipo genérico automaticamente, sem fornecer nada a ela.
type T<G = Record<string, any>> = {
id: keyof G
label: string
somethingElse?: string
}
Esta função retorna um objeto que possui uma propriedade especial id
, que deverá ter um tipo "random"
se source
a propriedade não for passada para ele. Se source
for aprovado, o retornado id
deverá obter o tipo desource
const element = <ID extends string = 'random'>({ source }: { source?: ID } = {}) =>
({
id: (source || 'random') as ID,
label: 'Element1',
}) as const satisfies T
// I don't want the return type to be "T", I want what it returns to satisfy "T".
// as you see I dont provide "somethingElse" key here, so I don't want it in the return type
type Data = { a: string; b: number }
Isso me dá o erro exato que desejo, mas apenas se eu usar variáveis:
const el1 = element() // el1 gets type { readonly id: "random"; readonly label: "Element1"; }
const el2 = element({source: 'b'}) // el2 gets type { readonly id: "b"; readonly label: "Element1"; }
const el3 = element({source: 'else'}) // el3 gets type { readonly id: "else"; readonly label: "Element1"; }
const b: T<Data>[] = [el, el2, el3] // el1 and el3 invalid, el2 valid. It is all correct
Mas por que isso é válido quando eu uso diretamente sem variável? Deve gerar um erro
const a: T<Data>[] = [element()]
// No generic or property is provided to it "element()",
// why the return type of "element()" is { readonly id: keyof Data; readonly label: "Element1"; } ??
TypeScript pode usar tipos de retorno de função como alvos de inferência , o que significa que uma função genérica pode ter seus parâmetros de tipo inferidos pelo tipo contextual de seu retorno, bem como pelos tipos conhecidos de seus argumentos. Em
o compilador espera
[element()]
ser do tipoT<Data>[]
e, portanto,element()
ser do tipoT<Data>
e, portanto ,ID
serkeyof Data
e não há erro.Se você não gosta disso e deseja que o tipo de retorno não seja usado como site de inferência, você pode usar o
NoInfer
tipo de utilitário para bloquear a inferência dessa posição:Nos casos em que
ID
não foi inferido a partir do tipo de retorno, isso não deverá ter efeito e todos os outros exemplos são iguais:Mas agora você obtém o erro desejado no seu último exemplo, já que o
T<Data>
contexto não afetaID
. E comoID
agora não tem nenhum site de inferência, ele volta ao padrão"random"
:Link do Playground para o código