Wie bekommt man den strikten Typ eines Werts in TypeScript?
Zum Beispiel habe ich eine Funktionssignatur wie folgt:
declare function foo<T>(input: T): T;
und ich hoffe, dass es den strikten Typ des Eingabeobjekts zurückgibt, ohne den Vorlagentyp manuell festzulegen:
const bar = foo({ str: 'foo', bool: true })
Der erwartete Typ von bar ist: { str: 'foo', bool: true }
anstatt { str: string; bool: boolean }.
Antwort #1
Ab TypeScript 3.4 schreiben
const bar = foo({ str: 'foo', bool: true } as const)
Antwort #2
Ich bin ein großer Fan von as const und der Funktionalität, die es ermöglicht. Das Problem dabei ist, dass der Aufrufer und nicht die Funktion entscheidet, ob literal types verwendet werden sollen oder nicht. Dies kann zu Verwirrung bei den Anwendern von foo führen, da die Leute wahrscheinlich vergessen werden, as const hinzuzufügen, und sie werden an anderen Stellen seltsame Fehler erhalten, wenn die Typen keine literal types sind.
Wenn wir uns auf die übliche Weise stützen, wie Literaltypen in TypeScript abgeleitet werden, können wir foo dazu bringen, Literaltypen aus seinem Parameter ableiten zu lassen:
declare function foo<
T extends Record<string, V>,
V extends string | boolean | number | symbol | null | undefined | Record<string, V>
>(input: T ): T;
const bar = foo({ str: 'foo', bool: true, o: { bar: "bar", n: 1 } });
// const bar: {
// str: "foo";
// bool: true;
// o: {
// bar: "bar";
// n: 1;
// };
// }
Die obige Lösung funktioniert für verschachtelte Objekte und sollte in den meisten Fällen gut funktionieren und erspart es den Aufrufern, as const hinzuzufügen. Diese Lösung funktioniert in 3.4 und früher. Sie beruht auf der Tatsache, dass TypeScript Literaltypen beibehält, wenn sie einem Typ-Parameter zugewiesen werden, der auf einen Typ beschränkt ist, der der Basistyp für Literaltypen sein kann.
