TypeScript 中应如何声明一个函数,之后给它添加静态属性?
发布于 6 年前 作者 xyzingh 11815 次浏览 来自 问答

反面例子1:

function abc(a: string, b: number): void;
function abc(a: string): void;
function abc(a: any, b:any): void {
	if (typeof b === 'number'){}
	else {}
}
abc.someAttr = ()=>{};

反面例子2:

interface IAbc {
	(a: string, b: number): void;
	(a: string): void;
	someAttr: ()=>void;
}
let abc: IAbc = (a: any, b:any) => {
	if (typeof b === 'number'){}
	else {}
}
abc.someAttr = ()=>{};

现在这样凑合着:

interface IAbc {
	(a: string, b: number): void;
	(a: string): void;
	someAttr?: ()=>void; // 加了个问号
}
let abc: IAbc = (a: any, b?:any) => {
	if (typeof b === 'number'){}
	else {}
}
abc.someAttr = ()=>{};

请问有人知道正确手法吗?

22 回复

为啥不弄个类然后内部函数弄成静态?

1、你把IAbc定义为返回值了 2、a,b定义为any也不合适 正确写法:

interface IAbc {
  a: string;
  b?: number;
}

function abc(iabc: IAbc): void {
  if(typeof iabc.b == 'number') {

  } else {

  }
}

但是有个问题是你说的静态属性,TS应该是没有这个东西的 你可以使用类,类有静态属性,但似乎不是你想要的

interface IAbc { (a: string, b: number): void; (a: string): void; } 这是函数重载。后面要写any来实现。

IAbc不是abc的返回值类型,就是它的类型啊?

@xyzingh 我知道,返回值相同没必要重载,重载是针对返回不同的类型,可选属性就可以了

@xyzingh image.png 你的意图是定义类型,实际上你最后的代码定义的是返回值 你把类型定义在这里了 image.png 你认为和这个有什么区别 let abc = (a: any, b: any): IAbc =>

ts视频教程看看,希望对你有帮助: https://pan.baidu.com/s/17jllW0igIOWjM3YCvWS-bg

楼主用的什么ide? 你这代码全部都会报类型错误啊 首先ts没有重载,你想想ts是要编译成js的,函数也就是原型链上的对象,是不可能一条链绑两个同名属性的. 如果要做你类似的东西,应该用默认参数 其次你那个明明是定义了一个对象的声明,但给了一个函数. 而且函数带静态属性本身就是很诡异的事情. 老老实实类加静态变量加静态方法不好么?

class A {
    static someAttr = "";

    fun1(a: string, b: number = 0) {
    }
}

@JsonSong89
有重载啊,看看文档去 “首先ts没有重载,你想想ts是要编译成js的,函数也就是原型链上的对象,是不可能一条链绑两个同名属性的.” 1、首先TS只是在做类型检查,并没有绑定,只是更容易让你发现错误,重载是解决针对输入不同,返回不同类型值的类型检查的 2、”函数也就是原型链上的对象“,最好还是区分开,a function () {} , let ressult = a(); const b = { a : 1}, let res = b.a;

@JsonSong89 给的反面例子,自然会报类型错误。第三个凑合的例子是通过的。 TS有重载: https://www.typescriptlang.org/docs/handbook/functions.html#overloads 并且可以声明接口给函数用 https://www.typescriptlang.org/docs/handbook/interfaces.html#function-types 接口里声明多个函数类型是重载的本质。 请自己补课 @fuxingZhang "你认为和这个有什么区别 let abc = (a: any, b: any): IAbc => {…}" 这样执行 abc(…, …); 得到的应是IAbc类型,也就是一个函数且有属性someAttr IAbc我是用在abc上的,不是abc执行得到的返回值啊。

重载只是随手举个例子,帖子问的是定义函数添加静态属性。

@xyzingh image.png ”得到的应是IAbc类型,也就是一个函数且有属性someAttr“ 是对象,不是函数 你的写法就是在定义返回值,和我写的那个是一样的,而你的意图是定义参数,所以你写的和你想要的不一样

@fuxingZhang 嗯,这里是我没说清楚,ts只是类型声明时的重载,编译后就没了. 后面那个是语病,我是想说(你这两个)函数不可能同时存在于一条链上(不同链会覆盖).

这样?

interface IAbc {
    (a: string, b?: number): void
    [propName: string]: () => void | undefined
}

const abc = ((a: string, b?: number) => {
    if (typeof b === 'number') {
        console.log(b)
    } else {
        console.log(a)
    }
}) as IAbc

abc.someAttr = () => {
    console.log('some attr')
}

abc('hello')
abc('hello', 123)
abc.someAttr()

哈,我刚想到改过来,你就发了。

不写在 class 里 可读性太差了,

function abc(){
};
function staticMethod(){
}
abc.staticMethod = staticMethod;

微软不推荐ts (IAbc) 这个写法。

interface F { (): any; someValue: number } const f: F = Object.assign(() => {}, { someValue: 3 })

没搞懂,静态方法貌似只有类里面的方法有,普通方法没有静态方法这个概念吧。void的意义应该是无有效返回值,不是静态方法,这个概念都不一样。

时隔一个月回来补上正确做法。 https://www.tslang.cn/docs/handbook/declaration-merging.html

function buildLabel(name: string): string {
    return buildLabel.prefix + name + buildLabel.suffix;
}

namespace buildLabel {
    export let suffix = "";
    export let prefix = "Hello, ";
}

@xyzingh 现在尽量少用namespace了吧。那是ecma模块系统前的一个解决方案

官方描述混合类型:接口能够描述JavaScript里丰富的类型。 因为JavaScript其动态灵活的特点,有时你会希望一个对象可以同时具有上面提到的多种类型。

interface IAbc {
	(a: string, b: number): void;
	(a: string): void;
	someAttr: ()=>void; // 可以不加问号
}
// 混合类型
let abc = <IAbc>(a: any, b?:any) => {
	if (typeof b === 'number'){}
	else {}
}
abc.someAttr = ()=>{};

const id = this.getTopicId()

回到顶部