tc39 / proposal-type-annotations

ECMAScript proposal for type syntax that is erased - Stage 1
https://tc39.es/proposal-type-annotations/
4.13k stars 44 forks source link

Suggestion: Make optional parameter syntax to be less specific. #174

Closed msadeqhe closed 1 year ago

msadeqhe commented 1 year ago

I suggest to change optinal parameter syntax from separator?: string:

function split(str: string, separator?: string) {
    // ...
}

to separator: ?string:

function split(str: string, separator: ?string) {
    // ...
}

or to separator: string?:

function split(str: string, separator: string?) {
    // ...
}

That change will simplify and make this proposal to be more general (and less specific to current type-checkers). In this way everything specific to type-checkers will be after colon :.

carycodes commented 1 year ago

I disagree. The question mark there isn't just part of the parameter's type--it applies to and changes the signature of the function, making that parameter optional. If a syntax like separator: string? did exist, I would intuitively expect the question mark to be part of the type of the parameter, which would make it roughly equivalent to separator: string|undefined.

Some Typescript examples for extra clarity:

function f(s?: string) {}
f(); // valid
f(undefined); // valid (a little weird, but weird in the same way that javascript is weird about function params

function g(s: string|undefined) {}
g(); // NOT valid, s is mandatory
g(undefined); // valid
ljharb commented 1 year ago

The existing syntactic indicator that a function parameter is option is "does it have a default". There's just no need for a question mark at all.

acutmore commented 1 year ago

For context a prefixed ? is a valid Flow type annotation: https://flow.org/en/docs/types/maybe/

carycodes commented 1 year ago

The existing syntactic indicator that a function parameter is option is "does it have a default". There's just no need for a question mark at all.

That's an excellent point, but I think it's a matter of convenience. f(s:string|undefined=undefined) is certainly a mouthful compared to f(s?:string). Whether that pattern is common enough to warrant a special shorthand is an interesting question. TypeScript seems to think it is, but I don't personally have a strong opinion.

ljharb commented 1 year ago

f(s:string = undefined). That it's string | undefined inside the function is statically implied, and that it's string outside the function is also statically implied. There's no reason to conflate the external and internal types :-)

spenserblack commented 1 year ago

The existing syntactic indicator that a function parameter is option is "does it have a default".

I 99% agree with this, but there are some instances where an argument might be optional, yet not have a default. Referring to another language, Python, getattr has the usage getattr(object, name[, default]) -> value. When the named attribute does not exist on the object, it raises an exception if the default is not defined, and returns the default if it is defined. This is why the function signature isn't getattr(object, name, default=None).

In JS/TS terms:

// Using Typescript for familiarity, apologies for showing bias to this type system

// This would probably use the arguments object
declare function getAttr(obj: object, name: string, def?: any): any;

getAttr({}, 'foo'); // raise exception
getAttr({}, 'foo', 'bar'); // return 'bar'
getAttr({}, 'foo', undefined); // return undefined

In this case, def: any=undefined might be confusing if it raises an error when arguments.length == 2. "Why does the first fail and the second work? They're both undefined!" might be a complaint.

IMO this is "weird JS," and not that necessary in a language with both null and undefined. This is just a hypothetical, and in real world usage I don't think this distinction matters that much for JavaScript, but I just wanted to throw that out there :slightly_smiling_face:

msadeqhe commented 1 year ago

Thanks.

Yes, Javascript already have ?? and ?. operators, thus allowing ?: within optional parameters seems natural and acceptable.

function split(str: string, separator?: string) {
    // ...
}

But making optional parameters notation to be after :, would make this proposal simpler and easier to be accepted in Javascript. I've created another issue for it.