TypeScript-infer-Schlüsselwort

infer ist ein Schlüsselwort in bedingten Typen von TypeScript, mit dem neue Typen aus vorhandenen Typen abgeleitet werden.

Es ermöglicht das Extrahieren und Ableiten von Typen innerhalb generischer bedingter Typen und erlaubt leistungsstarke Typoperationen.


SVG-Diagramm: Wie infer funktioniert Background Title How the infer keyword works Original Type Original Type type Promise<T> = { value: T } Arrow infer inference Inference result Extracted type type ValueOf<T> = T extends Promise<infer V> ? V : never Example Example ValueOf<Promise<string>> → string Lower half: Application scenarios Common use cases for infer Scenario 1 Extract Promise value type Scenario 2 Extract array element type Scenario 3 Extract function return type Arrow marker

Warum wird das infer-Schlüsselwort benötigt?

In der generischen Programmierung müssen wir oft Teiltypen aus komplexen Typen extrahieren.

Zum Beispiel ausPromise<string>extractstring, fromArray<User>extractUser。

Das infer-Schlüsselwort macht eine solche Typenextraktion elegant und typsicher. Es ermöglicht, eine Typvariable in einem bedingten Typ zu deklarieren und sie dann im wahren Zweig zu verwenden.

Konzepterklärung:infer ist die Abkürzung von "infer", was "ableiten" bedeutet. Es kann nur in der extends-Klausel eines bedingten Typs verwendet werden, um eine Typvariable zu deklarieren, die abgeleitet werden soll.


Grundlegende Verwendung

Verwende infer, um Typen in bedingten Typen abzuleiten.

Beispiel

// Den Werttyp aus Promise extrahieren
// Wenn T Promise<V> ist, V zurückgeben; andernfalls never zurückgeben
type ValueOf<T> = T extends Promise<infer V> ? V : never;

// Test
type Str = ValueOf<Promise<string>>;  // string
type Num = ValueOf<Promise<number>>; // number
type NotPrm = ValueOf<string>;        // never

// Anwendungsbeispiel
var promise: Promise<string> = Promise.resolve("hello");
var value: ValueOf<typeof promise> = "Welt";

console.log("Zeichenkettenextraktion: " + (typeof value === "string" ? "Erfolg" : "Fehler"));

Ausgabe:

String extraction: success

Erklärung:infer VEine Typvariable V wird deklariert, und TypeScript leitet den Typ von V automatisch ab.


Array-Elementtypen extrahieren

Den Elementtyp aus einem Array-Typ extrahieren.

Beispiel

// Elementtyp eines Arrays extrahieren
// Wenn T ein Array V[] ist, V zurückgeben
type ArrayElement<T> = T extends (infer V)[] ? V : never;

// Test
type User = { name: string };
type Users = User[];

type E1 = ArrayElement<string[]>;   // string
type E2 = ArrayElement<Users>;       // User
type E3 = ArrayElement<number>;       // never (kein Array)

// Anwendungsbeispiel
var users: Users = [{ name: "Alice" }];
var element: ArrayElement<Users> = users[0];

console.log("Elementtyp: " + element.name);

Anwendungsfälle:Dieses Muster wird häufig verwendet, um Elemente eines bestimmten Typs aus Union-Typen zu extrahieren.


Rückgabetypen von Funktionen extrahieren

Extrahiere den Rückgabetyp aus einem Funktionstyp.

Beispiel

// Rückgabetyp einer Funktion extrahieren
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;

// Test
function getData() {
    return { id: 1, name: "Alice" };
}
function fetchUser(id: number): Promise<User> {
    return Promise.resolve({ id, name: "Bob" });
}

type R1 = ReturnType<typeof getData>;  // { id: number; name: string }
type R2 = ReturnType<typeof fetchUser>; // Promise<User>

// Anwendungsbeispiel
var result: R1 = { id: 1, name: "Test" };
console.log("Rückgabetyp: " + JSON.stringify(result));

Eingebaute Typen:TypeScripts eingebauteReturnType<T>Utility-Typen werden mit infer implementiert.


Extrahieren von Funktionsparametertypen

Parametertypen aus einem Funktionstyp extrahieren.

< h2 class="example">Beispiel
// Den Typ des ersten Parameters einer Funktion extrahieren
type FirstParameter<T> = T extends (first: infer P, ...rest: any[]) => any ? P : never;

// Test
function createUser(name: string, age: number): Benutzer {
    return { id: 1, name };
}
function logMessage(msg: string): void {
    console.log(msg);
}

type P1 = FirstParameter<typeof createUser>; // string
type P2 = FirstParameter<typeof logMessage>;  // string
type P3 = FirstParameter<() => void>;          // never

// Anwendungsbeispiel
var nameParam: P1 = "Alice";
console.log("Parametertyp: " + nameParam);

Hinweis:Sie können verwenden...rest: any[]um beliebig viele verbleibende Parameter abzugleichen.


Mehrfaches infer

Verwendung von mehrfachem infer in einem bedingten Typ.

Beispiel

// Extrahiere die Typen der ersten beiden Elemente eines Tupels
type FirstTwo<T> = T extends [infer A, infer B, ...rest: any[]] ? [A, B] : never;

// Test
type Tuple = [string, number, boolean];
type FirstTwoTypes = FirstTwo<Tuple>; // [string, number]

// Objekteigenschaften extrahieren
type ObjectValue<T> = T extends { value: infer V } ? V : never;

type WithValue = { value: string; name: string };
type ExtractedValue = ObjectValue<WithValue>; // string

// Anwendungsbeispiel
var tupleResult: FirstTwoTypes = ["hello", 123];
console.log("Tupel: " + JSON.stringify(tupleResult));

Tupel:Verwenden...rest: any[]um die restlichen Elemente eines Tupels abzugleichen.


Verwendung von infer in rekursiven Typen

Verwenden Sie infer in rekursiven Typ-Dienstprogrammen, um komplexe Typoperationen zu implementieren.

Beispiel

// Tiefgehend schreibgeschützter Typ – rekursive Anwendung von infer
type DeepReadonly<T> = T extends Function
    ? T
    : T extends object
        ? { readonly [P in keyof T]: DeepReadonly<T[P]> }
        : T;

// Test
interface User {
    name: string;
    address: {
        city: string;
        zip: string;
    };
}

type ReadonlyUser = DeepReadonly<User>;

// Promise-Typen abflachen
type FlattenPromise<T> = T extends Promise<infer U>
    ? U extends Promise<any>
        ? FlattenPromise<U>
        : U
    : T;

type Nested = Promise<Promise<string>>;
type Flat = FlattenPromise<Nested>; // string

// Anwendungsbeispiel
var user: ReadonlyUser = {
    name: "Alice",
    Adresse: { Stadt: "Peking", Postleitzahl: "100000" }
};
// user.name = "Bob"; // Fehler: readonly
console.log("Tiefes readonly: " + user.name);

Rekursives infer:Die Verwendung von infer in rekursiven Typen ermöglicht tiefe Typumwandlungen, wie tiefes readonly, tiefes partial usw.


Hinweise

  • Kann nur auf der rechten Seite von extends verwendet werden:infer kann nur in der extends-Klausel eines bedingten Typs verwendet werden
  • Deklarieren von Typvariablen:Verwenden Sieinfer Vum die Typvariable zu deklarieren, die inferiert werden soll.
  • Mehrfache Verwendung erlaubt:Mehrere infer können in einem einzelnen bedingten Typ verwendet werden
  • Gibt never zurück, wenn die Inferenz fehlschlägt:Wenn die Inferenz fehlschlägt, gibt der bedingte Typ never zurück

Best Practices:infer ist der Kern der Implementierung benutzerdefinierter Utility-Typen; seine Beherrschung ermöglicht mächtige Typoperationen.


Zusammenfassung

infer ist eine der mächtigsten Funktionen im TypeScript-Typsystem.

  • Typ-Extraktion:Teiltypen aus komplexen Typen extrahieren
  • Bedingte Inferenz:Typen innerhalb bedingter Typen ableiten
  • Funktionsbezogen:Extrahieren von Funktionsparametern und Rückgabetypen
  • Rekursive Hilfstypen:Implementierung tiefer Typentransformationen

Empfehlung:Ein tiefes Verständnis von infer ermöglicht es Ihnen, fortgeschrittenere Typ-Hilfsmittel zu schreiben, was die Typsicherheit und die Entwicklungseffizienz verbessert.

Andere Erweiterungen