skrivning - Er der en TypeScript-kompilatorindstilling til at tvinge typekontrol på objektets egenskaber?
For at skrive mere robust kode, ser jeg på at bruge TypeScript til mine webbaserede projekter. Jeg har indtil videre relativt lidt erfaring med sproget, men jeg er stødt på et problem, som jeg har svært ved at finde information om.
Overvej TypeScript-koden nedenfor:
public static getResponseCode(resObj: object): number {
let c: number = resObj["c"]
return c;
}
Er der en måde, hvorpå jeg kan tvinge TypeScript-kompilatoren til at advare mig her og fortælle mig, at resObj["c"] måske ikke er et tal, og at jeg først skal tjekke, om det er et tal? F.eks. kan jeg tvinge TypeScript til at få mig til at omskrive koden som denne (eller noget lignende):
public static getResponseCode(resObj: object): number {
if (typeof resObj["c"] !== "number") { return APIResponseCode.UnknownFailure; }
let c: number = resObj["c"]
return c;
}
Jeg forventer, at jeg får de resultater, jeg gør, simpelthen fordi typen af resObj["c"] er any. Hvad kan jeg gøre her? Findes der et almindeligt mønster, der bruges i TypeScript?
Svar #1
Du kan slå noImplicitAny-compilerindstillingen til. Compileren vil så klage hver gang noget er implicit any.
Vi sætter noImplicitAny inde i tsconfig.json.
{
"compilerOptions": {
"noImplicitAny": true
}
}
Eller vi sætter det sådan her tsc --noImplicitAny fra kommandolinjen.
Det ville tvinge dig til at gøre noget.
For eksempel kunne du bruge enhver eksplicit.
public static getResponseCode(resObj: object): number {
const resAny = resObj as any;
if (resAny.c && typeof resAny.c !== "number") {
return APIResponseCode.UnknownFailure;
}
const c: number = resAny.c;
return c;
}
Eller du kunne bruge et interface med en unionstype og en typebeskytter.
interface ResObj {
c: boolean | string | number | object;
}
public static getResponseCode2(resObj: ResObj): number {
if (typeof resObj.c !== "number") {
return APIResponseCode.UnknownFailure;
}
const c: number = resObj.c;
return c;
}
Svar #2
TypeScript udfører ingen typekontrol under kørsel. Afhængigt af hvad du prøver at gøre, har du et par muligheder. Den første er at definere et interface for resObj:
interface ResObj { c: number; }
Nu
public static getResponseCode(resObj: ResObj): number {
let c: number = resObj.c;
return c;
}
Din kode vil ikke kompilere nu, hvis du sender getResponseCode noget, der ikke matcher ResObj (med en c-egenskab, som ikke er et tal).
Hvad hvis du vil, at c måske skal være et tal eller måske en streng? I så fald, brug en unionstype:
interface ResObj { c: number | string; }
Din oprindelige version af getResponseCode ovenfor vil nu fejle under kompilering. TypeScript vil klage over, at det ikke ved, hvordan man konverterer string | number til number.
Hvis du skriver koden, som du foreslog:
public static getResponseCode(resObj: ResObj): number {
if (typeof resObj.c !== "number") { return APIResponseCode.UnknownFailure; }
let c: number = resObj.c;
return c;
}
TypeScript vil være glad, da dets flowanalyse opdager typeof-kontrollen og ved, at når det når return-sætningen, kan c kun være et tal.
For mere komplekse situationer kan du bruge det, der kaldes en typebeskytter, som fortæller TypeScript eksplicit, at en bestemt funktion garanterer en bestemt type af dens parameter:
function isNumber(c: string | number): c is number {
return typeof c === 'number';
}
Nu kan du skrive
public static getResponseCode(resObj: ResObj): number {
if (!isNumber(resObj.c)) { return APIResponseCode.UnknownFailure; }
let c: number = resObj.c;
return c;
}
