Skip to content
New issue

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

Add a flag which priorities unknown over any in any | unknown #46347

Open
5 tasks done
orta opened this issue Oct 13, 2021 · 4 comments
Open
5 tasks done

Add a flag which priorities unknown over any in any | unknown #46347

orta opened this issue Oct 13, 2021 · 4 comments
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript

Comments

@orta
Copy link
Contributor

orta commented Oct 13, 2021

Suggestion

πŸ” Search Terms

any vs unknown, any strict, unknown strict, unknown as any, any as unknown in strict

βœ… Viability Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript/JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
  • This feature would agree with the rest of TypeScript's Design Goals.

⭐ Suggestion

We have a lot of cases where we'd like to have folks opt-in to unknown instead of any in the eslib, DOM, DT and modules. We've discussed internally about the idea of a third primitive, but that's tricky because it requires finding a good word to describe that, would break .d.ts backwards compatibility and that's quite a fine-grained change.

I propose that we have a flag which lets unknown beat any in union narrowing, which we class as a part of the stricter than strict category.

Today all the way back to 3.6:

type A = any | unknown
//   ^? - type A = any

A future release

// @thisCompilerFlag: true

type A = any | unknown
//   ^? - type A = unknown

πŸ“ƒ Motivating Example

Anywhere where we use any but would prefer to offer a way to provide unknown instead, for example:

  • JSON.parse
  • The fetch / axios APIs
  • new Object / Object.create

πŸ’» Use Cases

Where the ecosystem breakage for moving from any are too big to warrant the move. I think switching out any | unknown is a pretty reasonable syntax which doesn't add a new concept to the language. It means anyone can adopt support without having to force updating TypeScript versions.

@orta
Copy link
Contributor Author

orta commented Oct 13, 2021

Could maybe also be used for things like:

@remcohaszing
Copy link

I just though of an alternative solution which turns out to be really close to #45605

Add a compiler option to forcefully turn any or unknown types which originate from a .d.ts file into either any or unknown when it reaches user code (.ts file). A user could still decide to use the any or unknown type in their own code. I think this also aligns, or could even supersede "useUnknownInCatchVariables".

For example, given:

a.d.ts:

export declare const unknownA: unknown;
export declare const anyA: any;

b.ts:

export declare const unknownB: unknown;
export declare const anyB: any;

This would be the behaviour:

c.ts ({ "anyOrUnknownLibType": "as-is" } default)

import { unknownA, anyA } from './a';
import { unknownB, anyB } from './b';

// $ExpectType unknown
unknownA;

// $ExpectType any
anyA;

// $ExpectType unknown
unknownB;

// $ExpectType any
anyB;

c.ts ({ "anyOrUnknownLibType": "any" })

import { unknownA, anyA } from './a';
import { unknownB, anyB } from './b';

// $ExpectType any
unknownA;

// $ExpectType any
anyA;

// $ExpectType unknown
unknownB;

// $ExpectType any
anyB;

c.ts ({ "anyOrUnknownLibType": "unknown" })

import { unknownA, anyA } from './a';
import { unknownB, anyB } from './b';

// $ExpectType unknown
unknownA;

// $ExpectType unknown
anyA;

// $ExpectType unknown
unknownB;

// $ExpectType any
anyB;

I think the benefit of this is that:

  • Library types don’t need to be adjusted
  • The user is in control

@ITenthusiasm
Copy link

If possible, I think remcohaszing's #46347 (comment) may actually work out more cleanly.

The ability to simultaneously lighten the burden on authors and place control in the user's hands is pretty game changing. It would hopefully help reduce confusion too. (I feel like any | unknown could be confusing for some... and it would require some updates to the docs.)

@andrewbranch andrewbranch added Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript labels Nov 2, 2021
@43081j
Copy link

43081j commented Feb 21, 2023

can we possibly have a strict compiler flag which just introduces an extra built in library file? one which overrides the usual one, by setting various types to unknown

e.g. have it override JSON.parse to return unknown

we could then just maintain that alongside the standard lib files?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

5 participants