首页 > 解决方案 > 在 Typescript 模块中定义类

问题描述

我正在为外部库编写一个 Typescript 模块。

这是我的一块index.d.ts

declare module 'my-external-library' {
  export class MyComponent extends React.Component<MyComponentProps> {}

  export class CustomClass {
    constructor(
     firstParam: string,
     secondParam: string,
    )
  }

  interface MyComponentProps {
    config: string
    customClass: CustomClass
    text?: string
    customFn?: (input: string) => boolean
  }

}

customClass除了道具之外,这很好用。自定义类是一个必须是这样的类:

class customClass {
  constructor(firstParam, secondParam) {
    this.firstParam = firstParam
    this.secondParam = secondParam
  }

  ... all the methods you want
}

export default customClass

在一个单独的文件中,我将customClass道具提供给MyComponent,如下所示:


import customClass from './customClass'

<MyComponent
    config: "test"
    customClass: customClass
/>

customClass实际上没有收到在 中声明的“构造函数类型” index.d.ts,但组件的所有其他道具都运行良好。那么,我所做的类定义是正确的吗?我必须用另一种方法导出课程?

这是一个 CodeSandbox:https ://codesandbox.io/s/react-typescript-playground-forked-nrfk2

感谢您的帮助,请原谅我的经验不足

标签: javascripttypescripttypes

解决方案


我已经分叉并编辑了您的代码沙箱,请查看:

编辑 React Typescript Playground(分叉)

现在我要解释一些关于 typescript 中的类的事情,这确实很令人困惑。

部分原因是人们使用术语“类”来指代差异上下文中的差异事物。为了消除歧义,让我们使用更准确的术语。

构造函数

MyPuppy通常被称为“类”,但在 JS 术语中它也是“构造函数”。因此,让我们在整个讨论中坚持使用构造函数。

// javascript
class MyPuppy {}

实例

变量puppy是一个实例MyPuppet

// javascript
const puppy = new MyPuppet()

实例类型与构造函数类型

在 typescript 中,当你声明一个像下面这样的类时,你将隐式声明一个同名的实例类型!

这种行为让很多人感到困惑。简而言之,MyPuppy作为JS 变量持有一个构造函数,而MyPuppy作为TS 类型变量实际上持有一个实例类型

现在我们如何引用构造函数的类型MyPuppy,也就是构造函数类型?你应该从字面上使用typeof MyPuppy.

// typescript
class MyPuppet {}

type MyPuppetInstance = MyPuppet
type MyPuppetConstructor = typeof MyPuppet

我们已经消除了歧义,让我们做一些案例研究。

有一个类的“实例端”和“静态端”的概念,曾经记录在旧的 TS 手册中。基本上“实例端”对应于实例类型,“静态端”对应于构造函数类型

class MyPuppy {
  static getSpecies(dog: MyPuppy) {
    return dog.species
  }

  constructor(species: string) { this.species = species }

  species: string

  // [side note] above two lines can be combined as one:
  // constructor(public species: string) {}

  poop() { return '' }
}

type MyPuppetInstance = MyPuppet
type MyPuppetConstructor = typeof MyPuppet


var bar: MyPuppetConstructor = MyPuppy
var foo: MyPuppetInstance = new bar("shiba_inu")

上面的代码片段做了几件事。

  1. 声明一个名为的 JS构造函数MyPuppy
  2. 隐式声明一个 TS实例类型 MyPuppy
  3. 在“实例端”,foo是一个实例,并且有一个属性species和一个方法poop
  4. 在“静态方面”,bar是一个构造函数,它是一个可以调用的“新函数” new bar("shiba_inu"),并且还有一个静态方法getSpecies

现在在一个.d.ts文件中,我们如何声明上述类型?您可以使用interface关键字或type关键字。它们几乎没有区别。

// index.d.ts

interface MyPuppyInstance {
  species: string
  poop(): string
}

interface MyPuppyConstructor {
  new (species: string): MyPuppyInstance
  getSpecies(dog: { species: string }): string
}

type MyPuppyInstance2 = {
  species: string
  poop(): string
}

type MyPuppyConstructor2 = 
  (new (species: string) => MyPuppyInstance)
  & { getSpecies(dog: { species: string }): string }

推荐阅读