Hur man kräver en specifik sträng i TypeScript-gränssnitt
Jag skapar en TypeScript-definitionsfil för ett tredjeparts JavaScript-bibliotek. En av metoderna tillåter ett optionsobjekt, och en av egenskaperna i optionsobjektet accepterar en sträng från listan: "collapse", "expand", "end-expand" och "none".
Jag har ett gränssnitt för options-objektet:
interface IOptions {
indent_size?: number;
indent_char?: string;
brace_style?: // "collapse" | "expand" | "end-expand" | "none"
}
Kan gränssnittet upprätthålla detta, så att om du inkluderar ett IOptions-objekt med egenskapen brace_style, tillåter det endast en sträng som finns i den godtagbara listan?
Svar #1
Detta släpptes i version 1.8 som "stränglitertyper"
Vad är nytt i Typescript - Strängliteraltyper
Exempel från sidan:
interface AnimationOptions {
deltaX: number;
deltaY: number;
easing: "ease-in" | "ease-out" | "ease-in-out";
}
Svar #2
Prova detta
export type ReadingTypes = 'some'|'variants'|'of'|'strings';
export interface IReadings {
param:ReadingTypes
}
Redigera: Stort tack för rösterna, men, med tiden och eftersom jag utvecklats som utvecklare :), skulle jag nu i de flesta fall inte längre rekommendera detta tillvägagångssätt. Ja, det är fortfarande giltigt men poängen är att konstruktionen ovan är väldigt lik en enum-struktur, så varför inte använda enum istället (fördelar nedan):
export enum ReadingTypes {
Some = 'some',
Variants = 'variants',
Of = 'of',
Strings = 'strings',
}
export interface IReadings {
param: ReadingTypes
}
Fördelar: (Ja, kanske det är mer som IMHO, jag förstår, men, ändå)
- Det är mer läsbart när du ser det i koden, till exempel
if(item.reading === 'some') {
...
}
// vs
if(item.reading === ReadingTypes.Some) {
...
}
I det första fallet, när du läser koden, kunde du inte vid första anblick se att .reading-fältet bara kan innehålla några vissa parametrar, och inte som vilken strängvärde som helst.
- När du skriver koden kommer du att få bättre hjälp av din redigerare om du använder enums - det räcker att komma ihåg namnet på enum och skriva det så kommer den att visa alla varianter av enum. Ja, med den första typen ('some' | 'variants' ...) kan den också göra det, men den gör det mindre.. ähm.. ivrigt
Svar #3
TS erbjuder en typning för specifika strängvärden, som kallas String literal types.
Här är ett exempel på hur man använder dem:
type style = "collapse" | "expand" | "end-expand" | "none";
interface IOptions {
indent_size?: number;
indent_char?: string;
brace_style1?: "collapse" | "expand" | "end-expand" | "none";
brace_style2?: style;
}
// Ok
let obj1: IOptions = {brace_style1: 'collapse'};
// Compile time error:
// Type '"collapsessss"' is not assignable to type '"collapse" | "expand" | "end-expand" | "none" | undefined'.
let obj2: IOptions = {brace_style1: 'collapsessss'};
Svar #4
Från och med TypeScript 2.4 kan du använda strängenum
Jag föredrar detta tillvägagångssätt eftersom det undviker behovet av att ha samma hårdkodade sträng på mer än ett ställe.
Det är möjligt att skapa en enum där värdena är strängar
export enum VISIBILITY {
PUBLISH = "publish",
DRAFT = "draft"
}
Denna enum kan sedan användas som en typ på ett gränssnitt eller en klass
export interface UserOptions {
visibility: VISIBILITY
}
Svar #5
Kanske inte exakt vad du ville ha, men Enum:er verkar vara en perfekt lösning för dig.
enum BraceStyle {Collapse, Expand, EndExpand, None}
interface IOptions {
indent_size?: number;
indent_char?: string;
brace_style?: BraceStyle
}
Enums är dock nummerbaserade. Det innebär att under körning kommer ett verkligt värde för t.ex. BraceStyle.Collapse att vara 0 i detta fall. Men du kan använda dem med andra, även icke-typescript-skript, eftersom de kompileras till objekt. Så här kommer BraceStyle att se ut efter kompilering och körning:
{
0: "Collapse",
1: "Expand",
2: "EndExpand",
3: "None",
Collapse: 0,
Expand: 1,
EndExpand: 2,
None: 3
}
Om du istället vill ha strängar kan du använda en klass med statiska medlemmar, som beskrivs här
