typescript - Använda inbyggda typvaktsfunktioner för att förfina `unknown`/`object`-värde till en specifik objekttyp
Här är ett naivt försök:
const x: unknown = {a: 1};
if (
typeof x === 'object' &&
x !== null &&
'a' in x &&
typeof x.a === 'number' // error: Property 'a' does not exist on type 'object'.
) {
console.log("x's type is a subtype of {a: number}");
}
Finns det något sätt att använda inbyggda typvakter för att särskilja här?
Svar #1
För närvarande fungerar insnävning av en objekttyp via in-operatorn som k in o endast när o är av en unionstyp, och resultatet blir att unionstypen insnäs till endast de medlemmar som har en känd k-nyckel. Detta implementerades i microsoft/TypeScript#15256. Men i ditt fall, när du kontrollerar "a" in x, är den uppenbara typen för x bara object-typen, som inte är en union och inte har en känd "a"-nyckel. Så in-operatorkontrollen gör inget användbart för dig.
Det finns en öppen funktionsförfrågan på microsoft/TypeScript#21732 som ber om att in också ska begränsa icke-union-inmatningar genom att bekräfta att den kontrollerade egenskapen finns. Så något i stil med "a" in x bör begränsa x från object till {a: unknown}. Det är oklart när eller om detta kommer att implementeras i TypeScript. För tillfället finns det lösningar.
Till exempel kan du skapa din egen användardefinierade typvakt-funktion som beter sig som du vill att in ska bete sig, och sedan kalla på den istället för in. Ett sätt att göra detta kan vara:
function inOperator<K extends string, T extends object>(
k: K, o: T
): o is T & Record<K, unknown> {
return k in o;
}
Och observera att det uppfyller ditt användningsfall:
const x: unknown = { a: 1 };
if (
typeof x === 'object' &&
x !== null &&
inOperator('a', x) &&
typeof x.a === 'number' // okay
) {
x.a.toFixed(); // okay
console.log("x's type is a subtype of {a: number}");
}
När x.a.toFixed() anropas har x.a framgångsrikt smalnats till number.
Playground-länk till kod
