ChatGPT解决这个技术问题 Extra ChatGPT

有没有办法“提取” TypeScript 接口属性的类型?

假设库 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。我正在寻找一种在没有该声明的情况下实现这一目标的方法。

哪个不起作用 - 那是如何体现的?您看到的实际错误消息是什么?
@BartekBanachewicz 已更新

M
Michał Miszczyszyn

以前不可能,但幸运的是现在可以了,因为 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 引用一个值并且必须引用一个类型。我该怎么做呢?甚至有可能以任何方式吗?谢谢!
B
Ben Winding

要扩展已接受的答案,您还可以使用 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 };

G
Gabriel Petersson

keyof Colors 将返回所有键 "white" | "black" 的列表。当这个键列表被传递到颜色接口时,类型将是给定键的所有值,"#fff" | #000

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

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

J
James Bond

只是从联合对象类型中提取文字类型的示例:

type Config = {
    key: "start_time",
    value: number,
} | {
    key: "currency",
    value: string,
}

export type ConfigKey = Config["key"];
// "start_time"|"currency"


N
Noone

接口类似于对象的定义。然后 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 接口将是代码重复,需要不断更新。