Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
827 views
in Technique[技术] by (71.8m points)

Typescript: Type of a property dependent on another property within the same object

I have a TypeScript interface with two properties (type:string and args:object). The args may have different properties depending on the type. What type definition to I need to apply to args so the compiler/autocomplete will know which properties are allowed for args?

This is somewhat similar to how I use Actions in Redux, which do have a type and a payload and in my reducer the compiler knows by the switch-statement what the payload contains. But I can't get this to work with my object. I have read an excellent article here https://artsy.github.io/blog/2018/11/21/conditional-types-in-typescript/ but this describes the problem for a method with two args which depend on one another but not how to get this working for two properties within the same object.

export interface IObject {
  type: ObjectType
  parameters: ObjectParameters
}
export type ObjectType = "check" | "counter"
export interface IParametersCheck {
  checked: boolean
}
export interface IParametersCounter {
  max: number
  min: number
  step: number
}
export type ObjectParameters = IParametersCheck | IParametersCounter

If I have an IObject and set the type to "check" the compiler/autocomplete should offer the properties for IParametersCheck.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I think what you are actually looking for is a discriminated union. IObject should itself be a union:

export type IObject = {
    type: "checked"
    parameters: IParametersCheck
} | {
    type: "counter"
    parameters: IParametersCounter
}
export type ObjectType = IObject['type'] //// in case you need this union
export type ObjectParameters = IObject['parameters']  //// in case you need this union

export interface IParametersCheck {
    checked: boolean
}
export interface IParametersCounter {
    max: number
    min: number
    step: number
}

You could also do it with conditional types but I think the union solution works better :

export interface IObject<T extends ObjectType> {
    type: T
    parameters: T extends 'checked' ? IParametersCheck: IParametersCounter
}

Or with a mapping interface:

export interface IObject<T extends ObjectType> {
    type: T
    parameters: ParameterMap[T]
}
type ParameterMap ={
    'checked': IParametersCheck
    'counter': IParametersCounter
}

export type ObjectType = keyof ParameterMap

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...