【问题标题】:How to create a type from another type that has a specific property with diffente type in TypeScript?如何从 TypeScript 中具有不同类型的特定属性的另一种类型创建类型?
【发布时间】:2022-01-10 13:01:25
【问题描述】:

我有这种类型:

type Period = 'Monthly' | 'Yearly'
type Cycle = {
    period: Period,
    price: number
}

我想得到以下类型(基本上,允许句点为空字符串):

type Period = 'Monthly' | 'Yearly'
type EditableCycle = {
    period: Period | '',
    price: number
}

我正在考虑类似这样的组合语法:

type EditableCycle = Extend<Cycle, { period: '' }>

我怎样才能实现它?

原因,我希望用户在编辑时不能选择任何句点(因此句点可以是空字符串),但在验证后我确定句点将保持有效句点。

注意:真实类型比 Cycle 复杂得多,涉及数组和类似的东西,这是一个简化的例子。

【问题讨论】:

    标签: typescript types


    【解决方案1】:

    您可以使用Omit 实用程序类型来覆盖period 字段:

    type Period = 'Monthly' | 'Yearly'
    type Cycle = {
        period: Period,
        price: number
    }
    
    type EditableCycle = Omit<Cycle, "period"> & {
      period: Period | ''
    }
    
    const editableCycle: EditableCycle = {
      period: '',
      price: 5
    }
    

    如果此解决方案适合您,您可以更进一步,创建自己的 Override 类型,如下所示:

    type Period = 'Monthly' | 'Yearly'
    type Cycle = {
        period: Period,
        price: number
    }
    
    type Override<T, K> = Omit<T, keyof K> & K
    
    type EditableCycle = Override<Cycle, {
      period: Period | ''
    }>
    
    const editableCycle: EditableCycle = {
      period: '',
      price: 5
    }
    

    希望这个答案对您有所帮助。

    弗朗索瓦

    【讨论】:

      【解决方案2】:

      这是在您的问题中键入Extend 实用程序的方法(我已将其重命名为UnifyProps,因为它会生成一个新类型,包括两个参数中的所有属性,从而创建具有共享名称的属性类型的联合) :

      TS Playground link

      type UnifyProps<T1, T2> = {
        [K in keyof T1]: K extends keyof T2 ? (T1[K] | T2[K]) : T1[K];
      } & {
        [K in keyof T2]: K extends keyof T1 ? (T1[K] | T2[K]) : T2[K];
      };
      
      type Period = 'Monthly' | 'Yearly';
      
      type Cycle = {
        period: Period;
        price: number;
      };
      
      type EditableCycle = UnifyProps<Cycle, { period: '' }>;
      
      declare const ec: EditableCycle;
      ec.period = 'Monthly'; // ok
      ec.period = 'Yearly'; // ok
      ec.period = ''; // ok
      ec.period = 'another string'; /*
      ^^^^^^^^^
      Type '"another string"' is not assignable to type '"" | Period'. (2322) */
      

      【讨论】:

        【解决方案3】:

        或许你可以这样定义:

        type Period = 'Monthly' | 'Yearly'
        type Cycle = {
            period: Period,
            price: number
        }
        
        type Editable<T> =  {
          [K in keyof T]: T[K] extends string? (T[K] | '') : T[K];
        };
        
        type EditableCycle = Editable<Cycle>; // -->  period: "" | Period;
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2020-01-29
          • 2021-07-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多