为具有 none 或许多不同参数类型的函数定义 Typescript 类型
Define a Typescript type for a function with none or many different parameter types
我有一个将传递的函数绑定到 HTMLElement 的函数:
global.d.ts:
type tPrimitivRestParams = (number | object | string)[];
type tDefaultVoidFunction = (...params: tPrimitivRestParams) => void;
export default class AwesomeFunctions {
public static addClickCallback(id: HTMLElement, func: tDefaultVoidFunction, scope: object, ...argArray: tPrimitivRestParams): void {
[...] // checks
// eslint-disable-next-line no-null/no-null
element.onclick = func ? func.bind(scope, ...argArray) : null;
}
}
export default class AwesomeClass {
private bindMe(id: string):void {}
private bindMeToo():void {}
private bindMeThree(a:string, b: number, c: object): void {}
private bindMeFour(clazz: SomeClass): void {}
private binder():void {
AwesomeFunctions.addClickCallback(document.getElementById('...'), this.bindMeToo, this); // TS says yes
AwesomeFunctions.addClickCallback(document.getElementById('...'), this.bindMe, this, 'param'); // TS says no
AwesomeFunctions.addClickCallback(document.getElementById('...'), this.bindMeThree, this, 'param', 2, {whoopi: 'goldberg', age: 24, 'actual-age': 'dontcha dare askn!!!'}); // TS says no
AwesomeFunctions.addClickCallback(document.getElementById('...'), this.bindMeThree, this, new SomeClass()); // TS says no
}
}
它在 JS 上运行良好,但 TS 对除第一个以外的所有人大喊大叫:
// Example for bindMe
S2345: Argument of type '(id: string) => void' is not assignable to parameter of type 'tDefaultVoidFunction'.
如果我这样做:
AwesomeFunctions.addClickCallback(..., this.bindMe as tDefaultVoidFunction , ...);
TS满意,但我觉得不对
我知道这是 tDefaultVoidFunction 类型的问题。是否可以定义一个类型以使 TS 对所有绑定都满意?我不能使用 any、null 或 Function。
附带问题:
我也可以这样做:
AwesomeFunctions.addClickCallback(..., () => this.bindMe('param'), this);
TS 也很满意,但 95% 的 addClickCallback 函数变得毫无意义。但这并不是我犹豫是否使用箭头函数的原因。我担心范围可能会有所不同。据我所知,作用域始终是 this。所以在这种情况下,我声称箭头函数和绑定的行为相同。我错了吗?
可重现的例子:
type tPrimitivRestParams = (number | object | string)[];
type tDefaultVoidFunction = (...params: tPrimitivRestParams) => void;
class AwesomeFunctions {
public static addClickCallback(id: string, func: tDefaultVoidFunction, scope: object, ...argArray: tPrimitivRestParams): void {
// DO something
}
}
class AwesomeClass {
private bindMe(id: string):void {}
private bindMeToo():void {}
private bindMeThree(a:string, b: number, c: object): void {}
private binder():void {
AwesomeFunctions.addClickCallback('A', this.bindMeToo, this);
AwesomeFunctions.addClickCallback('B', this.bindMe, this, 'param');
AwesomeFunctions.addClickCallback('C', this.bindMeThree, this, 'param', 2, {whoopi: 'goldberg', age: 24, 'actual-age': 'dontcha dare askn!!!'});
}
}
游乐场:TS Example
这就是你告诉编译器的内容:
type tDefaultVoidFunction = (...params: (number | object | string)[]) => void;
回调必须接受任意数量的参数,其中每个参数必须接受数量 |对象 |字符串。
让我们看看你的函数...
const example: tDefaultVoidFunction = (id: string): void {}
该参数只接受字符串,因此编译器会告诉您这是错误的。 (缺少数字和对象)
您可以使用联合类型定义多个允许的签名:
type tDefaultVoidFunction = ((id: string) => void)
| (() => void)
| ((a: string, b: number, c: object) => void)
| ((clazz: SomeClass) => void);
备注:
private function bindMe(id: string):void {}
在 类 中没有有效的 TypeScript 代码,我想这只是一个错字。
- 文档:https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html
根据评论更新
可能的选项:
而不是写作:
AwesomeFunctions.addClickCallback(document.getElementById('...'), this.bindMeToo, this);
使用:
document.getElementById('...')?.addEventListener('click', (e) => this.bindMeTo());
// ignoring that we do not provide valid parameters in both cases
我有一个将传递的函数绑定到 HTMLElement 的函数:
global.d.ts:
type tPrimitivRestParams = (number | object | string)[];
type tDefaultVoidFunction = (...params: tPrimitivRestParams) => void;
export default class AwesomeFunctions {
public static addClickCallback(id: HTMLElement, func: tDefaultVoidFunction, scope: object, ...argArray: tPrimitivRestParams): void {
[...] // checks
// eslint-disable-next-line no-null/no-null
element.onclick = func ? func.bind(scope, ...argArray) : null;
}
}
export default class AwesomeClass {
private bindMe(id: string):void {}
private bindMeToo():void {}
private bindMeThree(a:string, b: number, c: object): void {}
private bindMeFour(clazz: SomeClass): void {}
private binder():void {
AwesomeFunctions.addClickCallback(document.getElementById('...'), this.bindMeToo, this); // TS says yes
AwesomeFunctions.addClickCallback(document.getElementById('...'), this.bindMe, this, 'param'); // TS says no
AwesomeFunctions.addClickCallback(document.getElementById('...'), this.bindMeThree, this, 'param', 2, {whoopi: 'goldberg', age: 24, 'actual-age': 'dontcha dare askn!!!'}); // TS says no
AwesomeFunctions.addClickCallback(document.getElementById('...'), this.bindMeThree, this, new SomeClass()); // TS says no
}
}
它在 JS 上运行良好,但 TS 对除第一个以外的所有人大喊大叫:
// Example for bindMe
S2345: Argument of type '(id: string) => void' is not assignable to parameter of type 'tDefaultVoidFunction'.
如果我这样做:
AwesomeFunctions.addClickCallback(..., this.bindMe as tDefaultVoidFunction , ...);
TS满意,但我觉得不对
我知道这是 tDefaultVoidFunction 类型的问题。是否可以定义一个类型以使 TS 对所有绑定都满意?我不能使用 any、null 或 Function。
附带问题:
我也可以这样做:
AwesomeFunctions.addClickCallback(..., () => this.bindMe('param'), this);
TS 也很满意,但 95% 的 addClickCallback 函数变得毫无意义。但这并不是我犹豫是否使用箭头函数的原因。我担心范围可能会有所不同。据我所知,作用域始终是 this。所以在这种情况下,我声称箭头函数和绑定的行为相同。我错了吗?
可重现的例子:
type tPrimitivRestParams = (number | object | string)[];
type tDefaultVoidFunction = (...params: tPrimitivRestParams) => void;
class AwesomeFunctions {
public static addClickCallback(id: string, func: tDefaultVoidFunction, scope: object, ...argArray: tPrimitivRestParams): void {
// DO something
}
}
class AwesomeClass {
private bindMe(id: string):void {}
private bindMeToo():void {}
private bindMeThree(a:string, b: number, c: object): void {}
private binder():void {
AwesomeFunctions.addClickCallback('A', this.bindMeToo, this);
AwesomeFunctions.addClickCallback('B', this.bindMe, this, 'param');
AwesomeFunctions.addClickCallback('C', this.bindMeThree, this, 'param', 2, {whoopi: 'goldberg', age: 24, 'actual-age': 'dontcha dare askn!!!'});
}
}
游乐场:TS Example
这就是你告诉编译器的内容:
type tDefaultVoidFunction = (...params: (number | object | string)[]) => void;
回调必须接受任意数量的参数,其中每个参数必须接受数量 |对象 |字符串。
让我们看看你的函数...
const example: tDefaultVoidFunction = (id: string): void {}
该参数只接受字符串,因此编译器会告诉您这是错误的。 (缺少数字和对象)
您可以使用联合类型定义多个允许的签名:
type tDefaultVoidFunction = ((id: string) => void)
| (() => void)
| ((a: string, b: number, c: object) => void)
| ((clazz: SomeClass) => void);
备注:
private function bindMe(id: string):void {}
在 类 中没有有效的 TypeScript 代码,我想这只是一个错字。- 文档:https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html
根据评论更新
可能的选项:
而不是写作:
AwesomeFunctions.addClickCallback(document.getElementById('...'), this.bindMeToo, this);
使用:
document.getElementById('...')?.addEventListener('click', (e) => this.bindMeTo());
// ignoring that we do not provide valid parameters in both cases