Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
130 views
in Technique[技术] by (71.8m points)

javascript - Why do I have to specify parameter names in a TS function type?

I am using typescript to write some function and this is the one that TS accepts:

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];
    }
};

But inithially I wanted to write the return type of useStorage in this way:

[T, (T) => Promise<void>]

Why TypeScript wants me to write down the newData name before the T occurs?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I think the closest thing you can hope for to a canonical answer is in the GitHub issues microsoft/TypeScript#13152 and microsoft/TypeScript#3081. The gist of the situation is this:

Supporting parameter names in function types is useful as documentation for functions and methods in libraries. A function type (username: string, password: string) => void is the same type as (arg0: string, arg1: string) => void, but the former probably helps developers write code more than the latter does. So support for type-annotated parameter names in function types is intended, documented in the (increasingly outdated) TypeScript spec, and used in libraries all over the place. In the words of one of the language maintainers:

I ... believe that it helps with documentation. Having used Haskell in the capacity that I have, I will say that omitting parameter names ... doesn't help anybody when they're learning a new library. While there's something to be said about an easier syntax, types being the only form of documentation for people often makes it difficult to understand intent ...


Furthermore, where type annotations on named values are supported in TypeScript, the types can be omitted and they will be inferred by the compiler. Failure to infer anything useful results in inferences of any. For example, in the following function:

function f(x, y): void { }
type F = typeof f;
// type F = (x: any, y: any) => void

the type of x and y is inferred as any (and you get a nice error with the --noImplicitAny compiler option). It's the same as the following annotated version:

function g(x: any, y: any): void { }
type G = typeof g;
// type G = (x: any, y: any) => void

Applying the same rule to the type signatures of f and g themselves leads to the following behavior:

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

So when you write (x, y) => void, the compiler interprets x and y as names and not as types. Since the type can be omitted, parameter names cannot. I don't think anyone likes this, but it's been this way for so long that it's apparently used in libraries, so changing this would break real-world code. From the same comment quoted above:

I think it is too late to make this sort of change. Because of the current behavior, interpreting a single identifier as a type would be a breaking change.


So that's the sad answer to this question. Maybe if they could go back in time they would make it so that the parameter name is optional and the type is required, to align more closely with type theory notation, but for now this is what we're stuck with.

Hope that helps; good luck!

Playground link to code


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...