javascript - 在 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
感谢您的帮助,请原谅我的经验不足
解决方案
我已经分叉并编辑了您的代码沙箱,请查看:
现在我要解释一些关于 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")
上面的代码片段做了几件事。
- 声明一个名为的 JS构造函数
MyPuppy
。 - 隐式声明一个 TS实例类型
MyPuppy
。 - 在“实例端”,
foo
是一个实例,并且有一个属性species
和一个方法poop
。 - 在“静态方面”,
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 }
推荐阅读
- r - 如何加快R中的for循环
- mysql - 为什么我在 laravel 迁移中得到指定的密钥太长?
- html - 如何以角度在一个csv文件中导出多个html表?
- android - GDB 显示“无法在核心文件中找到映射”
- javascript - 嵌套动态高度过渡效果
- java - 我的 gradle 同步不适用于 Intellij Idea
- php - 如何修复 Laravel 8 中的“此路由不支持 GET 方法”错误?
- blazor - 如何从 Blazor 调用 javascript 函数并取回数据(网络摄像头应用视频流并保存屏幕截图)?
- telegram - 如何排除名字中含有违禁词的访客?
- c - 删除循环双向链表中给定位置的节点