typescript - Vytvořit zpětné hledání typu pomocí klíčového slova infer?
Tady je to, co mám, mám různé typy a mám pro ten typ řetězcovou reprezentaci:
type PossibleValueTypes = Color | number | Position;
type PossibleValueTypesAsString = "color" | "number" | "position";
type ValueTypeMap = {
"color" : Color;
"number" : number;
"position" : Position;
};
Nyní, pokud máte dané řetězcové vyjádření, vrácení typu hodnoty je dost snadné, například:
function generateRandomValueOfType<T extends PossibleValueTypesAsString>(type: T) : ValueTypeMap[T] {
if (type === 'color') {
return {
r: 1,
g: 1,
b: 1,
a: 1,
} as ValueTypeMap[T]
}
if (type === "position") {
return {
x:1,
y: 1
} as ValueTypeMap[T]
}
if (type === "number") {
return 1 as ValueTypeMap[T];
}
throw new Error ("We shouldn't have got here");
};
const a: Position = generateRandomValueOfType("position");
const b: number = generateRandomValueOfType("position"); // Expected error!
Teď je otázka - co když chci udělat opak, to znamená - pokud mám datový typ hodnoty, určit jeho řetězcovou reprezentaci.
Nejlepší, co mám, je udělat řetězený podmíněný příkaz jako:
type ReverseValueTypeLookup<T extends PossibleValueTypes> = T extends Color ? "color" : T extends number ? "number" : T extends Position ? "position": never;
function hasAValueAcceptingCallback<T extends PossibleValueTypes> (callback: (value: T) => void, valueTypeAsString: ReverseValueTypeLookup<T>) {
const value = generateRandomValueOfType(valueTypeAsString);
//Argument of type 'ValueTypeMap[ReverseValueTypeLookup<T>]' is not assignable to parameter of type 'T'.
//'ValueTypeMap[ReverseValueTypeLookup<T>]' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'PossibleValueTypes'.
callback(value);
}
Ale to vlastně v příkladu, který jsem uvedl, nefunguje.
Existuje nějaký úhlednější způsob, jak dosáhnout obou věcí, které se tu snažím udělat?
TS hřiště
Odpověď č. 1
Docela rozvláčné, ale funkční řešení je...
type ReverseValueTypeLookup<T extends ValueTypeMap[keyof ValueTypeMap]> = {
[x in keyof ValueTypeMap]: ValueTypeMap[x] extends T ? x : never;
}[keyof ValueTypeMap];
// exclude key x when ValueTypeMap[x] is not assignable to T, and then get the types of values
type C = ReverseValueTypeLookup<Color>; // type 'color'
type N = ReverseValueTypeLookup<number>; // type 'number'
Pokud stále nedokážete rozlišit typy mezi Color | number | Position, použijte zužování typu jako...
var data: Color | number | Position;
if (typeof data === 'number') {
// data is number
} else if ('r' in data) {
// data is Color
} else if ('x' in data) {
// data is Position
}
