typescript - Hur deklarativt upprätthålla kompatibilitet mellan typer?
Jag skulle vilja upprätta en (kompileringstid) begränsning att en variabel av typen T2 kan tilldelas en variabel av typen T1.
Om jag har ett värde (t2) av typen T2 kan jag göra följande:
const t1: T1 = t2;
Finns det ett bättre sätt att göra detta på? Helst utan att behöva skapa ytterligare körningstidsenheter.
Jag definierar inte någon av dessa typer direkt i min applikation, så jag kan inte göra den ena till superklass för den andra.
Svar #1
Letar du efter ett vittne som kommer att ge dig ett kompilationsfel om T2 inte kan tilldelas T1 utan att något körs vid runtime? Självklart, du kan definiera något liknande detta:
type ExtendsWitness<U extends T, T> = U
och använd det så här:
type T2Witness = ExtendsWitness<T2, T1>
Om T2 kan tilldelas T1 kommer du inte få några fel. Annars kommer du få ett fel på det första typargumentet till ExtendsWitness som säger att T2 inte uppfyller begränsningen T1.
Här är ett exempel med några konkreta typer:
interface Super {
foo: string;
bar: number;
}
interface GoodSub {
foo: 'a';
bar: 3;
baz: boolean;
}
type GoodWitness = ExtendsWitness<GoodSub, Super> // okay
Observera att GoodSub inte definieras i termer av Super, men GoodSub bevittnas ändå av kompilatorn som en subtyp av Super. Här är ett exempel på en dålig subtyp:
interface BadSub {
foo: string;
baz: boolean;
}
type BadWitness = ExtendsWitness<BadSub, Super> // error
Kompilatorn kan inte se att BadSub är en subtyp av Super, och felet berättar exakt vad problemet är: Typen 'BadSub' uppfyller inte begränsningen 'Super'. Egenskapen 'bar' saknas i typen 'BadSub'.
Hoppas det hjälper; lycka till!
Svar #2
Jag tror inte att det du vill ha är uppnåeligt som det är. Förlåt för den dumma meningen, men så länge du inte kan definiera typernas relativitet => kan du inte definiera typernas relativitet.
Du har dock fortfarande följande alternativ:
Använd
any-typen för att enkelt tilldela värdenaconst t1: T1 = <any>t2; const t3: T2 = <any>t1;`Liknande lösning med en caster-funktion:
function toT1(t: T2): T1 { return <any>t; } const t1 = toT1(t2);Fördelen är att du inte behöver definiera typen t1.
Skapa en typ som slår samman två typer till en
type T3 = T1 | T2; const t1: T3 = t2;Detta löser problemet med tilldelning men kan leda till vissa problem med de enheter som redan är bundna till dessa T1 och T2. Detta kan användas situationsberoende beroende på behoven
Skapa en anpassad typvakt:
interface T1 { a: any; } interface T2 { b: any; } function isT1(t: T1 | T2): t is T1 { return true; } const t2: T2 = { b: 1 }; const t1: T1 = isT1(t2) ? t2 : null;Detta returnerar sant hela tiden så du kan tilldela din variabel till
t1utan några problem. Men detta är fortfarande fult.
Jag skulle välja alternativ nummer 1. Det är enkelt och täcker alla dina behov. Överdriven komplexitet är också dåligt.
