【问题标题】:Is there a way to "extract" the type of TypeScript interface property?有没有办法“提取” TypeScript 接口属性的类型?
【发布时间】:2016-07-18 14:25:56
【问题描述】:

假设库 X 有一个类型文件,其中包含一些接口。

interface I1 {
    x: any;
}
    
interface I2 {
    y: {
        a: I1,
        b: I1,
        c: I1
    }
    z: any
}

为了使用这个库,我需要传递一个与I2.y 完全相同类型的对象。我当然可以在我的源文件中创建相同的界面:

interface MyInterface {
    a: I1,
    b: I1,
    c: I1
}

let myVar: MyInterface;

但是我有责任让它与库中的那个保持同步,而且它可能非常大并导致大量代码重复。

因此,有没有办法“提取”接口的这个特定属性的类型?类似于 let myVar: typeof I2.y 的内容(不起作用并导致“找不到名称 I2”错误)。


编辑:在 TS Playground 中玩了一会儿后,我注意到以下代码完全符合我的要求:

declare var x: I2;
let y: typeof x.y;

但是,它需要声明一个冗余变量x。我正在寻找一种在没有该声明的情况下实现这一目标的方法。

【问题讨论】:

  • which doesn't work - 这如何体现?您看到的实际错误消息是什么?
  • @BartekBanachewicz 已更新

标签: typescript typing definitelytyped


【解决方案1】:

获取所有值,因为keyof Colors 返回了所有键的列表,这反过来又获取了Colors 接口的所有值

interface Colors {
  white: "#fff"
  black: "#000"
}

type ColorValues = Colors[keyof Colors]
// ColorValues = "#fff" | "#000"

【讨论】:

    【解决方案2】:

    这是我的问题陈述,我想将几​​个接口的属性类型合并为一种类型,这就是我所做的

    interface Fruit {
    name : string
    type : "Apple"
    }
    
    interface Fruit2 {
    name : string
    type : "Mango"
    }
    
    type FruitTypes = Fruit["type"] | Fruit2["type"]
    
    interface main {
    PK : string,
    SK :string,
    Type : FruitTypes 
    }
    
    const obj:main = {
    PK :"Some PK",
    SK :"Some SK",
    Type: "Mango"  // it can either be mango or apple only as in Fruit and Fruit2
    }

    【讨论】:

      【解决方案3】:

      要扩展已接受的答案,您还可以使用 type 关键字指定类型并在其他地方使用它。

      // Some obscure library
      interface A {
        prop: {
          name: string;
          age: number;
        }
      }
      
      // Your helper type
      type A_Prop = A['prop']
      
      // Usage
      const myThing: A_prop = { name: 'June', age: 29 };
      

      【讨论】:

        【解决方案4】:

        以前不可能,但幸运的是现在可以了,因为TypeScript version 2.1。它已于 2016 年 12 月 7 日发布,它引入了索引访问类型,也称为查找类型

        语法看起来与元素访问完全一样,但它是代替类型编写的。所以在你的情况下:

        interface I1 {
            x: any;
        }
        
        interface I2 {
            y: {
                a: I1,
                b: I1,
                c: I1
            }
            z: any
        }
        
        let myVar: I2['y'];  // indexed access type
        

        现在myVar 的类型为I2.y

        查看TypeScript Playground

        【讨论】:

        • 如果'y'是一个数组,有没有办法提取元素的类型?例如I2{ y: {..}[]}
        • @JohnB 是的,您可以以完全相同的方式进行操作,因为数组索引就像对象属性一样。在这里查看:typescriptlang.org/play/…
        • @JohnB 是的,您可以以相同的方式访问它,即。 I2['y'][0] 见:typescriptlang.org/play/…
        • 这个能力真的很棒
        • 假设我们正在循环使用I2 作为类型定义的对象的键。循环时如何动态获取特定键的类型。这; let z: typeof x[a];,其中a 是作为字符串的某个键,不起作用。它告诉我a 引用一个值并且必须引用一个类型。我该怎么做呢?甚至有可能以任何方式吗?谢谢!
        【解决方案5】:

        接口就像对象的定义。那么 y 是你的 I2 对象的一个​​属性,它属于某种类型,在这种情况下是“匿名的”。

        你可以使用另一个接口来定义 y,然后像这样使用它作为你的 y 类型

        interface ytype {
           a: I1;
           b: I1;
           c: I1;
        }
        
        interface I2 {
            y: ytype;
            z: any;
        }
        

        您可以将您的界面放在一个文件中并使用提取,以便您可以将其导入您项目的其他文件中

        export interface ytype {
           a: I1;
           b: I1;
           c: I1;
        }
        
        
        
         export interface I2 {
                y: ytype;
                z: any;
            }
        

        你可以这样导入:

           import {I1, I2, ytype} from 'your_file'
        

        【讨论】:

        • 一切都很好,但正如我所提到的 - 接口 I1 和 I2 来自外部库,并在该库的 d.ts 文件中定义。因此,拥有这个 ytype 接口将是代码重复,需要不断更新。
        猜你喜欢
        • 2019-09-24
        • 1970-01-01
        • 2021-02-04
        • 2021-06-28
        • 1970-01-01
        • 2022-11-13
        • 1970-01-01
        • 2020-04-08
        • 1970-01-01
        相关资源
        最近更新 更多