Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/typescript/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 为什么我必须在TS函数类型中指定参数名?_Javascript_Typescript_Generics_Typescript Generics - Fatal编程技术网

Javascript 为什么我必须在TS函数类型中指定参数名?

Javascript 为什么我必须在TS函数类型中指定参数名?,javascript,typescript,generics,typescript-generics,Javascript,Typescript,Generics,Typescript Generics,我正在使用typescript编写一些函数,这是TS接受的函数: export const useSomething = <T>() => { const useStorage = <T>(key: string, initialData: T) : [T, (newData: T) => Promise<void>] => { const [data, setState] = useState<T>(in

我正在使用typescript编写一些函数,这是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];
    }
};

为什么TypeScript要我在
T
发生之前写下
newData
名称?

好吧,您正在定义一个参数,参数需要名称。否则,您将如何引用它?我的意思是,在调用
setItem
时,您正在使用
newData
。您不能简单地使用
setItem(t)
,它将类似于使用
setItem(string)
,这肯定不是您想要的。
我说“类似”,因为
string
在JavaScript中是一个有效的对象,您可以将其作为参数传递<但是,code>T可以是任何东西,可能只是一个类型定义,并且这些类型在编译过程中消失。

我认为您最希望得到规范答案的是GitHub问题和。情况的要点是:

函数类型中支持的参数名作为库中函数和方法的文档很有用。函数类型
(用户名:string,密码:string)=>void
(arg0:string,arg1:string)=>void
的类型相同,但前者可能比后者更能帮助开发人员编写代码。因此,我们打算在函数类型中支持类型注释参数名称,并将其记录在中(越来越过时),并在各地的库中使用

我。。。相信它有助于文档编制。以我现有的能力使用Haskell之后,我会说省略参数名。。。在学习新图书馆的时候,对任何人都没有帮助。虽然有一些关于更简单语法的话要说,但类型作为人们文档的唯一形式,常常使理解意图变得困难


此外,如果TypeScript中支持命名值上的类型注释,则可以省略这些类型,并且编译器将对它们进行推断。未能推断出任何有用的结果将导致推断出
any
。例如,在以下函数中:

function f(x, y): void { }
type F = typeof f;
// type F = (x: any, y: any) => void
x
y
的类型被推断为
any
(使用
--noImplicitAny
可以得到一个很好的错误)。与以下注释版本相同:

function g(x: any, y: any): void { }
type G = typeof g;
// type G = (x: any, y: any) => void
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
因此,当您编写
(x,y)=>void
时,编译器将
x
y
解释为名称,而不是类型。因为类型可以省略,所以参数名不能省略。我不认为有人喜欢这样,但这种方式已经存在很长时间了,所以改变它会破坏现实世界的代码。根据上面引用的同一评论:

我认为现在做出这样的改变已经太晚了。由于当前的行为,将单个标识符解释为类型将是一个突破性的变化


这就是这个问题的悲哀答案。也许,如果他们能回到过去,他们会使参数名是可选的,类型是必需的,以便与类型理论符号更紧密地对齐,但现在这是我们所坚持的

希望有帮助;祝你好运


以下类型别名可用于避免显式参数名称:

type F<A extends unknown[], R> = (...args: A) => R

const example1: F<[number, boolean], number> = (x, y) => y ? x : x + 1;
const example2: F<[number], string> = String;
type F=(…args:A)=>R
常数示例1:F=(x,y)=>y?x:x+1;
常量示例2:F=字符串;

我没有定义参数,而是定义一个返回类型,如果返回类型不是匿名的(泛型不是匿名的),则返回类型与变量名无关。我仍然真诚地相信
[T,(T)=>Promise]
语法没有错。您不使用setItem(T),而是使用setItem(key)将键转换为T类型。这个答案并没有真正解决这个问题,这就是为什么函数类型需要参数名。类型
(x:T)=>void
(y:T)=>void
是相同的;参数名称是一个伪名称。我假设支持它们的原因是为了文档(类型为
(用户名:string,密码:string)=>void
的函数在文档中比
(string,string)=>void
更有用),需要它们的原因是一致性和易于解析,但这些只是我的猜测,我还没有标准答案。这是一个非常令人疲惫和有价值的答案——谢谢。使用TypeScript有时很奇怪,因为它解决了一些问题,但也带来了其他问题。匿名类型的值可以表示为
:T
,这有点混乱,但也比一个字母名称更明确,更不混乱,或者将复杂的类型延伸到几行,以便为半有意义的名称腾出空间。
type F<A extends unknown[], R> = (...args: A) => R

const example1: F<[number, boolean], number> = (x, y) => y ? x : x + 1;
const example2: F<[number], string> = String;