Bar*_*zek 3 javascript generics typescript typescript-generics
我正在使用打字稿编写一些函数,这是 TS 接受的函数:
export const useSomething = <T>() => {
const useStorage = <T>(key: string, initialData: T) : [T, (newData: T) => Promise<void>] => {
const [data, setState] = useState<T>(initialData);
const setData = async(newData: T) : Promise<void> => {
await storage.setItem<T>(key, newData);
};
return [data, setData];
}
};
Run Code Online (Sandbox Code Playgroud)
useStorage但最初我想这样写返回类型:
[T, (T) => Promise<void>]
Run Code Online (Sandbox Code Playgroud)
newData为什么 TypeScript 要我在发生之前写下名字T?
我认为最接近规范答案的是 GitHub 问题 microsoft/TypeScript#13152和microsoft/TypeScript#3081。情况的要点是这样的:
在函数类型中支持参数名称作为库中函数和方法的文档很有用。函数类型(username: string, password: string) => void与 类型相同(arg0: string, arg1: string) => void,但前者可能比后者更有助于开发人员编写代码。因此,旨在支持函数类型中的类型注释参数名称,记录在(越来越过时的)TypeScript 规范中,并在各地的库中使用。 用一位语言维护者的话来说:
我......相信它有助于文档。在以我拥有的能力使用 Haskell 之后,我会说省略参数名称......当他们学习一个新库时,对任何人都没有帮助。虽然有一些关于更简单的语法的说法,但类型是人们唯一的文档形式,通常很难理解意图......
此外,在 TypeScript 支持命名值的类型注释的情况下,可以省略类型,编译器会推断它们。未能推断出任何有用的结果会导致 的推断any。例如,在以下函数中:
function f(x, y): void { }
type F = typeof f;
// type F = (x: any, y: any) => void
Run Code Online (Sandbox Code Playgroud)
xand的类型y被推断为any(并且--noImplicitAny 编译器选项会出现一个很好的错误)。它与以下注释版本相同:
function g(x: any, y: any): void { }
type G = typeof g;
// type G = (x: any, y: any) => void
Run Code Online (Sandbox Code Playgroud)
将同样的规则的类型签名f和g自己导致以下行为:
type Fprime = (x, y) => void; // --noImplicitAny yells at you here
// type Fprime = (x: any, y: any) => void
type Gprime = (x: any, y: any) => void;
// type Gprime = (x: any, y: any) => void
Run Code Online (Sandbox Code Playgroud)
因此,当您编写时(x, y) => void,编译器将xand解释y为名称而不是类型。由于类型可以省略,参数名称不能。我认为没有人喜欢这种方式,但这种方式已经存在了很长时间,显然已用于库中,因此更改此方式会破坏现实世界的代码。来自上面引用的同一评论:
我认为现在做出这种改变为时已晚。由于当前的行为,将单个标识符解释为类型将是一个重大变化。
所以这就是这个问题的悲伤答案。也许如果他们能回到过去,他们会让参数名称是可选的,类型是必需的,以便与类型理论符号更紧密地对齐,但现在这就是我们所坚持的。
希望有所帮助;祝你好运!
| 归档时间: |
|
| 查看次数: |
471 次 |
| 最近记录: |