Achei que já tinha resolvido isso uma vez, mas agora estou tropeçando nisso de novo.
Considere esta união:
type Handler<T> = (value: T) => void;
type Foo = { a: string; b: Handler<string> } | { a : number; b: Handler<number> }
dado algum objeto x aderindo ao que Foo
eu gostaria de ser capaz de fazer
x.b(x.a);
sem obter alguma variante do erro:
Argument of type 'string | number' is not assignable to parameter of type 'never'.
Type 'string' is not assignable to type 'never'.(2345)
Esta é uma tentativa que venho explorando, mas não produz um resultado diferente:
type Handler<T> = (value: T) => void;
type Correlated<A> = A extends string ? Handler<string> :
A extends number ? Handler<number> :
never;
type Foo<A extends string | number = string | number> = {
a: A;
b: Correlated<A>;
};
function apply<T extends Foo<A>, A extends string | number = T["a"]>(x: T) {
x.b(x.a);
}
Existe uma maneira de restringir o tipo de propriedade correlacionada correta Foo.b a partir do tipo Foo.a ?
Primeiro, não há união discriminada, pois você não pode discriminar por tipos amplos como
string
ounumber
(em vez disso, use literais de string ou números, uma dica: você deve conseguir usarExclude
no tipo).Em relação à sua primeira tentativa, um membro de função em uma união intersecta seus parâmetros, então você tem
string & number = never
. Você pode restringir com uma proteção de tipo personalizada:Parque infantil
Reavaliar sua segunda tentativa com um tipo genérico condicional pode ser complicado para o TS, então sua avaliação é adiada. Felizmente, você não precisa usar um tipo condicional; removê-lo faz o código funcionar. Mas lembre-se de que o código genérico é diferente, pois permite
{a: string | number, b: (arg: string | number) => void}
:Parque infantil