繁体   English   中英

如何在 typescript 中使用泛型类型和联合类型

[英]How to use generic type and union types in typescript

我有一个 class,当我初始化它时,我传入一个值,或者一个关于该值的 object

例如

new Field<string>('test')
new Field<string>({value: 'test', inactive: 'preview'})

state.value是错误的。 (“FieldState”类型上不存在属性“值”。类型“T”上不存在属性“值”.ts(2339))

interface BoxedValue<T> {
  value: T 
  inactive: 'disabled'| 'preview'| 'hidden'
}

type FieldState<T> = BoxedValue<T> | T

class Field<T> {
  value: T
  _pendingValue: T

  constructor(state: FieldState<T>) {
    if(typeof state === 'object') {
      this.value = this._pendingValue = state.value
    } else {
      this.value = this._pendingValue = state
    }
  }
}

谢谢你的解决方案,我修改了代码,但我现在有一个新问题。

class Field<T> {
  value: T
  _pendingValue: T

  constructor(state: FieldState<T>) {
    if(this._isBoxedValue(state)) {
      this.value = this._pendingValue = state.value // Property 'value' does not exist on type 'FieldState<T>'.Property 'value' does not exist on type 'T'.
    } else {
      this.value = this._pendingValue = state
      // Type 'FieldState<T>' is not assignable to type 'T'.
      // T' could be instantiated with an arbitrary type which could be unrelated to 'FieldState<T>'.
     // Type 'BoxedValue<T>' is not assignable to type 'T'.
     // 'T' could be instantiated with an arbitrary type which could be unrelated to 'BoxedValue<T>'
    }
  }
  _isBoxedValue(state: FieldState<T>): boolean{
    return typeof state === 'object' && state !== null &&
      Object.keys(state).length === 2 && 'value' in state && 'inactive' in state;
  }
}

为什么我把判断条件放在isboxedvalue function里面会出错,而在构造函数里面却没有?

问题

嗨,问题是没有任何事情不会发生在每个人身上。 您的typeof state === "object"是对 BoxedValue 的测试,但有一个小错误:T 也可以是 object。

解决方案 1

  • 再增加一项测试
interface BoxedValue<T> {
    value: T;
    inactive: 'disabled' | 'preview' | 'hidden';
}

type FieldState<T> = BoxedValue<T> | T;

class Field<T> {
    value: T;
    _pendingValue: T;

    constructor(state: FieldState<T>) {
        if (typeof state === 'object' && "value" in state) {
            this.value = this._pendingValue = state.value;
        } else {
            this.value = this._pendingValue = state;
        }
    }
}

解决方案 2

  • 指定 T 的类型
interface BoxedValue<T> {
    value: T;
    inactive: 'disabled' | 'preview' | 'hidden';
}

type FieldState<T> = BoxedValue<T> | T;

class Field<T extends (string | number /* or your type */)> {
    value: T;
    _pendingValue: T;

    constructor(state: FieldState<T>) {
        if (typeof state === 'object') {
            this.value = this._pendingValue = state.value;
        } else {
            this.value = this._pendingValue = state;
        }
    }
}

您应该使用in运算符。 Using typeof state ==='object' can only guarantee that state is of object type(if the value of state is null , it's a object type as well), but cannot guarantee that it has a value property.

in 运算符还充当类型的缩小表达式。

interface BoxedValue<T> {
  value: T 
  inactive: 'disabled'| 'preview'| 'hidden'
}

type FieldState<T> = BoxedValue<T> | T

class Field<T> {
  value: T
  _pendingValue: T

  constructor(state: FieldState<T>) {
    if('value' in state) {
      this.value = this._pendingValue = state.value
    } else {
      this.value = this._pendingValue = state
    }
  }
}

更新:

您应该为_isBoxedValue方法使用用户定义的类型保护。 返回类型state is BoxedValue<T>是类型谓词,而不是boolean

例如

interface BoxedValue<T> {
  value: T 
  inactive: 'disabled'| 'preview'| 'hidden'
}

type FieldState<T> = BoxedValue<T> | T

class Field<T> {
  value: T
  _pendingValue: T

  constructor(state: FieldState<T>) {
    if(this._isBoxedValue(state)) {
      this.value = this._pendingValue = state.value;
    } else {
      this.value = this._pendingValue = state;
    }
  }
  _isBoxedValue(state: FieldState<T>): state is BoxedValue<T>{
    return typeof state === 'object' && state !== null &&
      Object.keys(state).length === 2 && 'value' in state && 'inactive' in state;
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM