Typescript - Как использовать интерфейс для создания нового объекта, соответствующего другой структуре - PullRequest
0 голосов
/ 08 апреля 2019

Я хочу создать объект, используя значения по умолчанию для интерфейса, но на В то же время меняется структура объекта. Например, для этого интерфейса:

interface IPerson {
  name: string
  age: number
}

Я хочу создать объект, подобный этому:

const person: IPerson = {
  name: {
    type: String,
    required: true
  },
  age: {
    type: Number,
    required: true
  }
}

Единственный способ, который я нашел, - это добавить тип объекта к name и age из интерфейс IPerson, например:

interface IPerson {
  name: string | IProp
  age: number | IProp
}

interface IProp {
  type: any
  required?: boolean
  // ...
}

Я не хочу менять оригинальный интерфейс IPerson. Так я был думая о чем-то вроде этого:

const person: IProperties<IPerson> = {
  // use properties of IPerson to determine which key/value pairs are valid in this object
}

Ответы [ 2 ]

2 голосов
/ 08 апреля 2019

Вы можете сделать это, используя условные типы и сопоставленные типы.

interface IPerson {
name: string
age: number
ocupation?: string
}

type PropertyType<T> = 
    [T] extends [string] ? typeof String :
    [T] extends [number] ? typeof Number :
    [T] extends [Date] ? typeof Date :
    [T] extends [Function] ? typeof Function : // add any other types here
    new (...a:any[]) => T // default must be a constructor for whatever T is 

type IfRequired<T, K extends keyof T, IfYes, IfNo> =
    Pick<T, K> extends Required<Pick<T, K>> ? IfYes : IfNo

type PropertyDefinition<T> = {
    [P in keyof T]-?: {
        type: PropertyType<Exclude<T[P], null | undefined>> // will not work for unions!
        required: IfRequired<T, P, true, false>
    }
}

let personDefinition: PropertyDefinition<IPerson> ={
    age : {
        required: true,
        type: Number
    },
    name: {
        required: true,
        type: String,
    },
    ocupation: {
        required: false,
        type: String
    }
} 
2 голосов
/ 08 апреля 2019

Вы можете использовать сопоставленный тип :

interface IPerson {
  name: string
  age: number
}

type IProperties<T> = {
    [K in keyof T]: IProp
}

interface IProp {
  type: any
  required?: boolean
  // …
}

const person: IProperties<IPerson> = {
    // …
}
...