typescript - Sjekk om et grensesnitt har et påkrevd felt


Er det mulig å sjekke om et grensesnitt har et obligatorisk felt ved hjelp av Typescripts betingede typer?

type AllRequired = { a: string; b: string }
type PartiallyRequired = { a: string; b?: string }
type Optional = { a?: string; b?: string }

// Is it possible to change this, so the below works
type HasRequiredField<T> = T extends {} ? true : false

type A = HasRequiredField<AllRequired> // true
type B = HasRequiredField<PartiallyRequired> // true
type C = HasRequiredField<Optional> // false

Svar #1

Ja, du kan oppdage om egenskaper er valgfrie. Det blir litt usikkert med indeks-signaturer, men typene dine har dem ikke, så jeg kommer ikke til å bekymre meg for dem.

Her er hvordan du kan hente bare nøklene til de ikke-valgfrie egenskapene til en objekttype

type RequiredKeys<T> = { [K in keyof T]-?:
  ({} extends { [P in K]: T[K] } ? never : K)
}[keyof T]

Og så kan du bare sjekke om den har noen av dem eller ikke (hvis RequiredKeys<T> er never, så har den ikke noen):

type HasRequiredField<T> = RequiredKeys<T> extends never ? false : true

Og det gir de ønskede resultatene dine:

type A = HasRequiredField<AllRequired> // true
type B = HasRequiredField<PartiallyRequired> // true
type C = HasRequiredField<Optional> // false

Håper det hjelper; lykke til!

Svar #2

Fant en annen, enklere måte å gjøre dette på som fungerer i minst TS 3.8.3.

// if Partial<T> extends T none of the fields are required.
type HasRequiredFields<T> = Partial<T> extends T ? false : true

Eksempelbrukstilfeller

type Info<TInfo> = Partial<TInfo> extends TInfo
   ? { info?: TInfo }
   : { info: TInfo };

type A = { type: 'A' } & Info<{ abc?: string }>
type B = { type: 'B' } & Info<{ abc: string }>

// Valid
let a1: A = { type: 'A' };
// Valid
let a2: A = { type: 'A', info: {} };
// Valid
let a3: A = { type: 'A', info: { abc: 'hello' } };
// Invalid
let a4: A = { type: 'A', info: { abc: 3 } };

// Invalid
let b1: B = { type: 'B' }
// Invalid
let b2: B = { type: 'B', info: {} };
// Valid
let b3: B = { type: 'B', info: { abc: 'Hello' } };
// Invalid
let b4: B = { type: 'B', info: { abc: 5 } };

Relaterte artikler