Jak wymagać określonego ciągu w interfejsie TypeScript


157

Tworzę plik definicji TypeScript dla biblioteki js innej firmy. Jedną z metod pozwala na obiekcie opcje, a jedną z właściwości obiektu opcje akceptuje ciąg z listy: "collapse", "expand", "end-expand", i "none".

Mam interfejs dla obiektu opcji:

interface IOptions {
  indent_size?: number;
  indent_char?: string;
  brace_style?: // "collapse" | "expand" | "end-expand" | "none"
}

Czy interfejs może to wymusić, więc jeśli dołączysz IOptionsobiekt do brace_stylewłaściwości, zezwoli tylko na ciąg, który znajduje się na liście akceptowanych?


4
Proszę ponownie zapoznać się z odpowiedziami na to pytanie
Andreas

Podobnie jak w komentarzu @Andreas, dlaczego wolisz odpowiedź RyanQ od odpowiedzi Denisa Khaya ? Denis wydaje się szerzej stosowalne imo.
ruffin

Odpowiedzi:


249

Zostało to wydane w wersji 1.8 jako „typy literałów tekstowych”

Co nowego w maszynopisie - typy literałów ciągów

Przykład ze strony:

interface AnimationOptions {
  deltaX: number;
  deltaY: number;
  easing: "ease-in" | "ease-out" | "ease-in-out";
}

6
Wymaga kopiowania i wklejania linii z ciągami znaków wszędzie tam, gdzie w aplikacji trzeba byłoby przekazać ciąg tego typu jako argument. Jeśli zawsze używasz całych AnimationOptions, to rozwiązanie wydaje się w porządku, ale w przypadkach użycia, w których możesz przejść tylko typ „easing”, jest błędne. Zobacz odpowiedź Denisa Khaya, jest o wiele lepiej.
Patryk Wlaź

150

Spróbuj tego

export type ReadingTypes = 'some'|'variants'|'of'|'strings';

export interface IReadings {
   param:ReadingTypes
}

14
Należy to oznaczyć jako poprawne, ponieważ umożliwia to ponowne użycie utworzonego typu w dowolnym miejscu aplikacji.
Patryk Wlaź

Właśnie tego szukałem jako sposobu na przekazanie tablicy ciągów jako wartości do wyliczonego typu. Pomijając całkowicie wyliczenie i używając type, mogłem przekazać następujący przykład: const myVar: ReadingTypes = ["some"|"variants"];zachowując jednocześnie dynamiczną składnię typowania wyliczeniowego. Całkowicie się zgodziłem, że to powinna być odpowiedź oznaczona jako poprawna.
mdawsondev

czy istnieje sposób na użycie tego, ale miękko wpisany w ten sposób type VisibilityTypes = VISIBILITY.PUBLISH | VISBIBILITY.DRAFT, otrzymuję błąd nie znaleziono przestrzeni nazw, jednak kiedy twardo je koduję, wydaje się, że działa
Max Carroll

Znalazłem sposób i dodałem nową odpowiedź
Max Carroll

11

Może nie do końca to, czego chciałeś, ale Enumwydaje się, że jest to idealne rozwiązanie dla Ciebie.

enum BraceStyle {Collapse, Expand, EndExpand, None}

interface IOptions {
  indent_size?: number;
  indent_char?: string;
  brace_style?: BraceStyle
}

Wyliczenia są jednak oparte na liczbach. Oznacza to, że w czasie działania rzeczywistą wartością np. BraceStyle.CollapseBędzie w tym przypadku 0. Ale możesz ich używać z innymi, nawet nie-maszynowymi skryptami, ponieważ kompilują się do obiektów. Oto jak BraceStylebędzie wyglądać po kompilacji i uruchomieniu:

{
    0: "Collapse",
    1: "Expand",
    2: "EndExpand",
    3: "None",
    Collapse: 0,
    Expand: 1,
    EndExpand: 2,
    None: 3
}

Jeśli chcesz zamiast tego łańcuchy, możesz użyć klasy ze statycznymi składowymi, jak opisano tutaj


enums mogą mieć wartości ciągów (przynajmniej teraz, nie jestem pewien, czy mogą w 2014). enum BraceStyle { Collapse = "Collapse", Expand = "Expand" }.
ZachB

Gdyby mogli w 2014 roku, wspomniałbym o tym w mojej odpowiedzi.
Kuba Jagoda

11

TS oferuje wpisywanie określonych wartości łańcuchowych, które są nazywane typami literałów String .

Oto przykład, jak z nich korzystać:

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'};

3

Od wersji TypeScript 2.4 można używać wyliczeń typu String

Preferuję to podejście, ponieważ pozwala uniknąć konieczności posiadania tego samego zakodowanego łańcucha w więcej niż jednym miejscu.

Możliwe jest wykonanie wyliczenia, w którym wartości są ciągami

export enum VISIBILITY {
  PUBLISH = "publish",
  DRAFT = "draft"
}

Tego wyliczenia można następnie użyć jako typu w interfejsie lub klasie

export interface UserOptions  {
  visibility:  VISIBILITY 
}

1
function keysOf<T>(obj: T, key: keyof T) { return obj[key]; }
interface SomeInterface {
   a: string;
}
const instance: SomeInterface = { a: 'some value'};
let value = keysOf<SomeInterface>(instance, 'b'); // invalid
value =  keysOf<SomeInterface>(instance, 'a'); // valid
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.