typescript - Nume de proprietate de tip mapat cu tip diferit


Imaginează-ți aceste tipuri de copaci:

type A1 = { m1: boolean };
type A2 = { m2: number };
type B = { m1: string; m2: string };

Vreau să creez un tip nou care trebuie să aibă aceeași denumire a proprietății, dar poate fi de propriul său tip. De exemplu, uniunea dintre A1 și A2 are aceeași denumire a proprietății ca B cu tipuri diferite, ceea ce este în regulă.

Exemplu așteptat:

type SafeRetype<T, Z extends T> = { 
    [K in keyof T]?: Z[K]; // This is where I need help
};

type C1 = SafeRetype<B, A1 | A2>; // Expect  { m1?: string; m2?: string };

Exemplu de eșec așteptat:

type D1 = { z: string };
type Err = SafeRetype<B, D1>; // Expect error because missing "z" does not exist in B (m1|m2)

Scopul pe care încerc să îl ating este să pot avea tipul principal care descrie structura proprietăților și apoi să mă asigur că celălalt tip are doar (toate sau parțial) proprietățile din primul tip, având libertatea de a schimba tipul proprietăților.

Teren de joacă

Răspuns #1

În cazul tău, A1 | A2 nu extinde B

Pentru a-l face să accepte doar obiecte care au aceeași cheie, poți defini că al doilea tip generic ar trebui să fie un obiect cu aceleași chei ca primul și orice valoare:

type SafeRetype<T, Z extends Record<keyof T, any>> = Partial<T>

sau

type SafeRetype<T, Z extends { [key in keyof T]: any}> = Partial<T>

În acest caz va apărea o eroare atunci când se încearcă utilizarea D1


O altă opțiune ar fi

type SafeRetype<T, Z> = Z extends Record<keyof T, any> ? Partial<T> : never

type Err = SafeRetype<B, D1>;

nu va rezulta într-o eroare pe a doua linie, dar valoarea va fi never și eroarea va apărea de fiecare dată când încerci să atribui ceva pe ea

Răspunsul #2

Este puțin ambigu ce anume cerințele și cazurile tale de utilizare exacte sunt. Dar se pare că ai nevoie doar de o combinație a intersecției dintre A1 și A2, folosind maparea proprietăților de tip (plus parametri opționali) pentru a suprascrie tipurile @ fiecare cheie.

type A1 = { m1: boolean };
type A2 = { m2: number };

type B = {
    [key in keyof (A1 & A2)]?: string;
}

Editare: în mod natural, acest lucru ar putea fi transformat destul de ușor într-un „generic” reutilizabil:

type A1 = { m1: boolean };
type A2 = { m2: number };

type B<T, N> = {
    [key in keyof T]?: N;
}

type C = B<A1 & A2, string>;