Búsqueda de sitios web

¿Cómo crear el equivalente de las clases de variantes de enum de Rust, o las clases selladas de Kotlin en TypeScript?


Me gustaría crear un tipo variante en TypeScript, para respuestas HTTP, que pueda tener varios estados. En Rust, podría crear este tipo como:

enum Response<T> {
    Empty,
    Loading,
    Failure(String),
    Success(data: T),
}

Lo mismo se podría hacer en Kotlin usando clases selladas:

sealed class Response<out: T> {
  object Empty: Response<Nothing>()
  object Loading: Response<Nothing>()
  class Failure(val err: string): Response<Nothing>()
  class Success(val data: T): Response<T>
}

¿Hay alguna manera de crear este tipo de variante en TypeScript?

Respuesta #1

Gracias a @gabriele-petrioli por la idea de usar una unión discriminada.

type EmptyState = {
  kind: "empty";
};

type LoadingState = {
  kind: "loading"
};

type FailedState = {
  kind: "failed"
  msg: string;
};

type SuccessState<T> = {
  kind: "success"
  data: T;
};

type RequestState<T> =
  | EmptyState
  | LoadingState
  | FailedState
  | SuccessState<T>;

function parse<T>(res: RequestState<T>) {
  switch (res.kind) {
    case "failed":
      res.msg;
      break;
    case "success":
      res.data;
  }
}

Respuesta #2

Aquí hay un tipo genérico que construye la unión automáticamente.

También he incluido una función utilidad intoEnum para facilitar su uso.

type PartialRustEnum<K extends string, V> = {
    kind: K
} & {
    [P in K]: V
}

export type RustEnum<T> = {
    [K in keyof T & string]: PartialRustEnum<K, T[K]>;
}[keyof T & string]

export function intoEnum<K extends string, V>(kind: K, value: V): PartialRustEnum<K, V> {
    return { kind, [kind]: value } as any
}

uso :

type FooOrBar = RustEnum<{
    foo: number
    bar: string
}>

let a: FooOrBar = intoEnum('foo',32)

if(a.kind === 'foo'){
  // inferred as foo
  console.log(a.foo)
}else{
  // inferred as bar
  console.log(a.bar)
}



Artículos relacionados