We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
You can continue the conversation there. Go to discussion →
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
最近在用 ts 写一些东西,上次写 ts 还是去年的尝试。。。开门见山吧:
遇到一个 debounce 场景,我熟练的找到之前的 js 代码:
export const debounce = (fn, ms = 300) => { let timer; return function debounced(...args) { clearTimeout(timer); timer = setTimeout(() => { fn.call(this, ...args); }, ms); }; };
然后随便改了改:
export const debounce = (fn: Function, ms: number = 300): Function => { let timer: number; return function debounced(...args: any[]) { clearTimeout(timer); timer = setTimeout(() => { fn.call(this, ...args); }, ms); }; };
然后 vscode 就划了两道红线:
第一个还好,搜了一下,因为 Node 里 setTimeout 返回值跟浏览器不一样。我看有些答案说让改成 window.setTimeout,我第一时间就照做了,显然这样一点都不优雅,没有兼容 nodejs 的使用场景。Typescript 有个关键字typeof,可以取到 setTimeout 的类型,然后再配合 ReturType,轻松取到 setTimeout 返回值:
typeof
let timeoutId = ReturnType<typeof setTimeout>;
第二个问题,简单,ThisParameterType 嘛,取 fn 的 this 类型,顺便加个泛型:
type NoReturFn = (this: any, ...args: any[]) => void; export function debounce<F extends NoReturFn>(fn: F, ms: number = 300): F { let timeoutId: ReturnType<typeof setTimeout>; return function debounced(this: ThisParameterType<F>, ...args: any[]) { clearTimeout(timeoutId); timeoutId = setTimeout(() => { fn.call(this, ...args); }, ms); }; }
一保存,又飘红了:
不能将类型“(this: ThisParameterType<F>, ...args: any[]) => void”分配给类型“F”。 "(this: ThisParameterType<F>, ...args: any[]) => void" 可赋给 "F" 类型的约束,但可以使用约束 "NoReturFn" 的其他子类型实例化 "F"。ts(2322)
我:???F 不是约束了就是这种格式吗? 到这里我其实想了老半天,中间搜过别人的实现,看过@types/lodash。但他们写的都太应付了,returnType 写的都是 Function,这不坐实AnyScript? 一时半会儿没能解决,心态有点崩:
AnyScript
- return function debounced... + return <F>function debounced...
这样确实消除了警告,但我越想越不服,凭啥不能分配给 F? 我猜想可能是 F 并不一定会遵守 NoReturnFn 的格式(指 return void,我试了下有 return 值的函数确实可以传进去且不报错:
const wtf: () => void = () => 1;
但是这样就是可以(符合直觉地)报错,完全搞不懂:
const wtf1: () => undefined | void = () => 1;
后来翻到这么一句话:
How to ensure a generic function passed to a higher order function has void return type? I think the best thing to do here is probably to embrace TypeScript's viewpoint that a void return type means "ignore any value returned" and not "no value is returned", and move on.
大概明白了,但是为啥我在官方文档里没看到过...
所以这个 NoReturnFn 是没有效果的,除非改成:
- type NoReturnFn = (this: any, ...args: any[]) => void; + type NoReturnFn = (this: any, ...args: any[]) => undefined | void
但是这样的话,() => undefined 也是被允许的了...所以好像是没有完美的 void return 写法了
但 debounced 的 return 值一定是 void,顺着这个思路,又改了一版:
type NoReturnFn = (this: any, ...args: any[]) => void; export function debounce<F extends NoReturnFn>( fn: F, ms: number = 300 ): (this: ThisParameterType<F>, ...args: any[]) => void { let timeoutId: ReturnType<typeof setTimeout>; return function debounced(this: ThisParameterType<F>, ...args: any[]) { clearTimeout(timeoutId); timeoutId = setTimeout(() => { fn.call(this, ...args); }, ms); }; }
好了,没有警告,没有报错,暂时就这样了。
后来又了解到:泛型的参数和函数的参数并不需要一一对应,精简了下:
export function debounce<T, P extends any[]>( fn: (this: T, ...p: P) => undefined | void, ms: number = 300 ) { let timeoutId: ReturnType<typeof setTimeout>; return function debounced(this: T, ...args: P) { if (timeoutId !== void 0) { clearTimeout(timeoutId); } timeoutId = setTimeout(() => { fn.call(this, ...args); }, ms); }; }
return undefined 也去掉:
How to ensure a generic function passed to a higher order function has void return type?
export function debounce<T, P extends any[], R>( fn: (this: T, ...p: P) => R & (void extends R ? void : never), ms: number = 300 ) { let timeoutId: ReturnType<typeof setTimeout>; return function debounced(this: T, ...args: P) { if (timeoutId !== void 0) { clearTimeout(timeoutId); } timeoutId = setTimeout(() => { fn.call(this, ...args); }, ms); }; }
新手上路,难免疏漏,多多理解,欢迎斧正。
The text was updated successfully, but these errors were encountered:
后来在使用过程中,又遇到一个报错,再当做装饰器的时候:
class A { @debounce public method() {} }
作为表达式调用时,无法解析方法修饰器的签名。 类型“(this: any, ...args: any[]) => void”与类型“TypedPropertyDescriptor<() => void>”不具有相同的属性。ts(1241) 类型“A”的参数不能赋给类型“NoReturFn”的参数。 类型“A”提供的内容与签名“(this: any, ...args: any[]): void”不匹配。ts(2345)
这个问题一开始也懵逼,后来查资料才知道方法装饰器的参数跟类装饰器不太一样。这个确实是知识盲区,没啥好说的,看看文档,封装了一个:
/** * @description 方法装饰器工厂:去抖 * @example ``` js * @Debounce(300) * public method() {} * ``` */ export function Debounce(ms: number = 300) { return function debounceDecorator( target: any, propertyKey: keyof typeof target, descriptor: TypedPropertyDescriptor<(...args: any[]) => void>, ) { const originFn = descriptor.value; if (typeof originFn === 'function') { const debouncedFn = debounce(originFn, ms); descriptor.value = debouncedFn; } }; }
这里又留下了一个问题没有解决,就是原生的 MethodDecorator: microsoft/TypeScript#17936
Sorry, something went wrong.
No branches or pull requests
最近在用 ts 写一些东西,上次写 ts 还是去年的尝试。。。开门见山吧:
正文
遇到一个 debounce 场景,我熟练的找到之前的 js 代码:
然后随便改了改:
问题
然后 vscode 就划了两道红线:


1
第一个还好,搜了一下,因为 Node 里 setTimeout 返回值跟浏览器不一样。我看有些答案说让改成 window.setTimeout,
我第一时间就照做了,显然这样一点都不优雅,没有兼容 nodejs 的使用场景。Typescript 有个关键字typeof
,可以取到 setTimeout 的类型,然后再配合 ReturType,轻松取到 setTimeout 返回值:2
第二个问题,简单,ThisParameterType 嘛,取 fn 的 this 类型,顺便加个泛型:
一保存,又飘红了:
我:???F 不是约束了就是这种格式吗?
到这里我其实想了老半天,中间搜过别人的实现,看过@types/lodash。但他们写的都太应付了,returnType 写的都是 Function,这不坐实
AnyScript
?一时半会儿没能解决,心态有点崩:
2.1
这样确实消除了警告,但我越想越不服,凭啥不能分配给 F?
我猜想可能是 F 并不一定会遵守 NoReturnFn 的格式(指 return void,我试了下有 return 值的函数确实可以传进去且不报错:
但是这样就是可以(符合直觉地)报错,完全搞不懂:
后来翻到这么一句话:
大概明白了,但是为啥我在官方文档里没看到过...
所以这个 NoReturnFn 是没有效果的,除非改成:
但是这样的话,() => undefined 也是被允许的了...所以好像是没有完美的 void return 写法了
3
但 debounced 的 return 值一定是 void,顺着这个思路,又改了一版:
好了,没有警告,没有报错,暂时就这样了。
优化
1
后来又了解到:泛型的参数和函数的参数并不需要一一对应,精简了下:
2
return undefined 也去掉:
新手上路,难免疏漏,多多理解,欢迎斧正。
The text was updated successfully, but these errors were encountered: