Búsqueda de sitios web

typescript - ¿Cómo hacer JSON con tipos seguros teniendo campos de tipo Enum?


Tengo algunos archivos JSON que cumplen con las interfaces de TypeScript que he definido.

En su mayor parte, al importar dichos archivos JSON y asignarlos a variables tipadas, TypeScript puede inferir automáticamente la firma de tipo (ver funciona exactamente como quiero en el código a continuación). Sin embargo, cuando el tipo incluye enumeraciones de cadenas, ya no funciona (ver NO funciona).

Lo siguiente es un Ejemplo Mínimo y Reproducible que funciona:

valid.json

{ "id": 3.14159 }

inválido.json

{ "id": "3.14159" }

validEnum.json

{ "color": "red" }

invalidEnum.json

{ "color": "chartreuse" }

index.ts

import validJson from './valid.json'
import invalidJson from './invalid.json'
import validJsonEnum from './validEnum.json'
import invalidJsonEnum from './invalidEnum.json'

type ColorType = 'red' | 'blue' | 'yellow'

type IJsonType = {"id": number}
type IJsonTypeWithEnum = {"color": ColorType}

// behaves exactly as I want
const a: IJsonType = validJson    // no error
const b: IJsonType = invalidJson  // ERROR: Type 'string' is not assignable to type 'number'.

// DOES NOT behave as I want: SHOULD NOT error
const c: IJsonTypeWithEnum = validJsonEnum    // ERROR: Type 'string' is not assignable to type 'ColorType'.

// DOES NOT behave as I want: error should be that "chartreuse" is not assignable to type 'ColorType'
const d: IJsonTypeWithEnum = invalidJsonEnum  // ERROR: Type 'string' is not assignable to type 'ColorType'.

Puedo hacer que el error desaparezca con type IJsonTypeWithEnum={"color": string}, pero eso derrota el propósito.

¿Existe algún recurso o una opción del compilador para hacer que TypeScript reconozca los valores de enum dentro de JSON como cadenas? ¿O es una limitación insalvable de TypeScript para la inferencia de tipos en JSON?

Respuesta #1

Intenta usar la afirmación de tipo

const data: IJsonType = jsonData as IJsonType;

Respuesta #2

Typescript no lo convertirá por ti en este caso. Necesitarás hacer la conversión de tipo tú mismo

type ColorType = 'red' | 'blue' | 'yellow';

type IJsonType = {"color" : ColorType}


let validJson = {
   "color": "red" as ColorType
  // or
  // "color": "red" as const
}


let invalidJson = {
   "color": "chartreuse"
}


const data1: IJsonType = validJson;  // this MUST NOT error

const data2: IJsonType = invalidJson;  

Artículos relacionados