GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — New 'unknown' top type by ahejlsberg · Pull Request #24439 · microsoft/TypeScript

Conversation

@ahejlsberg

@ahejlsberg Anders Hejlsberg (ahejlsberg) commented May 27, 2018 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

This PR adds a new top type unknown which is the type-safe counterpart of any. Anything is assignable to unknown, but unknown isn't assignable to anything but itself and any without a type assertion or a control flow based narrowing. Likewise, no operations are permitted on an unknown without first asserting or narrowing to a more specific type.

Note that this PR is technically a breaking change since unknown becomes a reserved type name.

// In an intersection everything absorbs unknown

type T00 = unknown & null;  // null
type T01 = unknown & undefined;  // undefined
type T02 = unknown & null & undefined;  // null & undefined (which becomes never in union)
type T03 = unknown & string;  // string
type T04 = unknown & string[];  // string[]
type T05 = unknown & unknown;  // unknown
type T06 = unknown & any;  // any

// In a union an unknown absorbs everything

type T10 = unknown | null;  // unknown
type T11 = unknown | undefined;  // unknown
type T12 = unknown | null | undefined;  // unknown
type T13 = unknown | string;  // unknown
type T14 = unknown | string[];  // unknown
type T15 = unknown | unknown;  // unknown
type T16 = unknown | any;  // any

// Type variable and unknown in union and intersection

type T20<T> = T & {};  // T & {}
type T21<T> = T | {};  // T | {}
type T22<T> = T & unknown;  // T
type T23<T> = T | unknown;  // unknown

// unknown in conditional types

type T30<T> = unknown extends T ? true : false;  // Deferred
type T31<T> = T extends unknown ? true : false;  // Deferred (so it distributes)
type T32<T> = never extends T ? true : false;  // true
type T33<T> = T extends never ? true : false;  // Deferred

// keyof unknown

type T40 = keyof any;  // string | number | symbol
type T41 = keyof unknown;  // never

// Only equality operators are allowed with unknown

function f10(x: unknown) {
    x == 5;
    x !== 10;
    x >= 0;  // Error
    x + 1;  // Error
    x * 2;  // Error
    -x;  // Error
    +x;  // Error
}

// No property accesses, element accesses, or function calls

function f11(x: unknown) {
    x.foo;  // Error
    x[5];  // Error
    x();  // Error
    new x();  // Error
}

// typeof, instanceof, and user defined type predicates

declare function isFunction(x: unknown): x is Function;

function f20(x: unknown) {
    if (typeof x === "string" || typeof x === "number") {
        x;  // string | number
    }
    if (x instanceof Error) {
        x;  // Error
    }
    if (isFunction(x)) {
        x;  // Function
    }
}

// Homomorphic mapped type over unknown

type T50<T> = { [P in keyof T]: number };
type T51 = T50<any>;  // { [x: string]: number }
type T52 = T50<unknown>;  // {}

// Anything is assignable to unknown

function f21<T>(pAny: any, pNever: never, pT: T) {
    let x: unknown;
    x = 123;
    x = "hello";
    x = [1, 2, 3];
    x = new Error();
    x = x;
    x = pAny;
    x = pNever;
    x = pT;
}

// unknown assignable only to itself and any

function f22(x: unknown) {
    let v1: any = x;
    let v2: unknown = x;
    let v3: object = x;  // Error
    let v4: string = x;  // Error
    let v5: string[] = x;  // Error
    let v6: {} = x;  // Error
    let v7: {} | null | undefined = x;  // Error
}

// Type parameter 'T extends unknown' not related to object

function f23<T extends unknown>(x: T) {
    let y: object = x;  // Error
}

// Anything but primitive assignable to { [x: string]: unknown }

function f24(x: { [x: string]: unknown }) {
    x = {};
    x = { a: 5 };
    x = [1, 2, 3];
    x = 123;  // Error
}

// Locals of type unknown always considered initialized

function f25() {
    let x: unknown;
    let y = x;
}

// Spread of unknown causes result to be unknown

function f26(x: {}, y: unknown, z: any) {
    let o1 = { a: 42, ...x };  // { a: number }
    let o2 = { a: 42, ...x, ...y };  // unknown
    let o3 = { a: 42, ...x, ...y, ...z };  // any
}

// Functions with unknown return type don't need return expressions

function f27(): unknown {
}

// Rest type cannot be created from unknown

function f28(x: unknown) {
    let { ...a } = x;  // Error
}

// Class properties of type unknown don't need definite assignment

class C1 {
    a: string;  // Error
    b: unknown;
    c: any;
}

Fixes #10715.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

alexrock, yortus, Kingwl, j-oliveras, ajafff, Jessidhia, ericanderson, zpdDG4gta8XKpMCd, krryan, ahagelstein, and 146 more reacted with thumbs up emoji alfaproject, yortus, Kingwl, j-oliveras, svieira, Jessidhia, ericanderson, zpdDG4gta8XKpMCd, krryan, pelotom, and 48 more reacted with hooray emoji yortus, Kingwl, j-oliveras, zpdDG4gta8XKpMCd, krryan, Ebuall, ibezkrovnyi, andrew-morris-orbis, alcuadrado, mohsen1, and 49 more reacted with heart emoji
All reactions
  • 👍 156 reactions
  • 🎉 58 reactions
  • ❤️ 59 reactions
Anders Hejlsberg (ahejlsberg) added 17 commits May 26, 2018 08:07
@ahejlsberg
Rename existing unknownType to errorType
07a696f
@ahejlsberg
Free up one bit in TypeFlags
8f193b4
@ahejlsberg
Accept new baselines
8b2149e
@ahejlsberg
Add 'unknown' keyword to scanner/parser/emitter
03f464f
@ahejlsberg
Accept new baselines
d225065
@ahejlsberg
Implement 'unknown' type in checker
2003b2a
@ahejlsberg
Accept new baselines
5a0910a
@ahejlsberg
'null' and 'undefined' are bottom types in non-strictNullChecks mode
b20925a
@ahejlsberg
Fixes to keyof and narrowing by typeof check
9e4d19f
@ahejlsberg
Accept new baselines
f63b61c
@ahejlsberg
{ [P in unknown]: XXX } should resolve to { [x: string]: XXX }
79e7700
@ahejlsberg
Add tests
73af0ad
@ahejlsberg
Accept new baselines
5da063f
@ahejlsberg
Check we have non-unknown where we require non-nullable
353802c
@ahejlsberg
Add new diagnostic
a83653e
@ahejlsberg
Update tests
31c73de
@ahejlsberg
Accept new baselines
a4a73df
@ahejlsberg Anders Hejlsberg (ahejlsberg) changed the title New 'unknown New 'unknown' top type May 27, 2018
@ahejlsberg
Anders Hejlsberg (ahejlsberg) requested review from Daniel Rosenwasser (DanielRosenwasser), Mohamed Hegazy (mhegazy) and Wesley Wigham (weswigham) May 27, 2018 22:55
@RyanCavanaugh

Ryan Cavanaugh (RyanCavanaugh) commented May 29, 2018

Copy link
Copy Markdown
Member

Where'd we end up with mapped conditional types w.r.t unknown ?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@weswigham

Wesley Wigham (weswigham) commented May 29, 2018 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

type T41 = keyof unknown; // string | number | symbol

Does that make sense (is this derived from something else)? If unknown is effectively the infinite union - a union of all possible types would have no common keys among all of them, leading me to believe the correct result is never (the given types seem correct for never, this being a place where any is more never-like than top-like).

glentakahashi reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ahejlsberg

Anders Hejlsberg (ahejlsberg) commented May 29, 2018

Copy link
Copy Markdown
Member Author

Wesley Wigham (@weswigham) No, that probably doesn't make sense. We should be similar to keyof {} and keyof object here, both of which are never.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@ahejlsberg

Anders Hejlsberg (ahejlsberg) commented May 29, 2018

Copy link
Copy Markdown
Member Author

Ryan Cavanaugh (@RyanCavanaugh) Do you mean the behavior of unknown in a distributive conditional type? It's an atomic type so it doesn't distribute. This is unlike {} | null | undefined which distributes and therefore is very hard to test for.

RyanCavanaugh, aikoven, HermannGruber, hardfist, vassudanagunta, and AntoniBLopez reacted with thumbs up emoji
All reactions
  • 👍 6 reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

Anders Hejlsberg (ahejlsberg) added 3 commits May 29, 2018 12:54
@ahejlsberg
keyof unknown should be never
074961f
@ahejlsberg
Update tests
c694ffe
@ahejlsberg
Accept new baselines
e98f9a6
weswigham
Wesley Wigham (weswigham) reviewed May 29, 2018
View reviewed changes
Comment thread src/compiler/checker.ts

// Functions with with an explicitly specified 'void' or 'any' return type don't need any return expressions.
if (returnType && maybeTypeOfKind(returnType, TypeFlags.Any | TypeFlags.Void)) {
if (returnType && maybeTypeOfKind(returnType, TypeFlags.AnyOrUnknown | TypeFlags.Void)) {

@weswigham Wesley Wigham (weswigham) May 29, 2018

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a function returning an explicit unknown should probably have return values? Otherwise you should've written void or undefined, right?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

mhegazy, gcnew, and melissab1238 reacted with thumbs up emoji
All reactions
  • 👍 3 reactions

@ahejlsberg Anders Hejlsberg (ahejlsberg) May 29, 2018

Copy link
Copy Markdown
Member Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure about that. undefined is in the domain of unknown (just like it is in the domain of any) and that's really what should guide us here.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@weswigham Wesley Wigham (weswigham) May 29, 2018

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm. Fair. Do we handle unions with undefined in accordance with that, then?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@ahejlsberg Anders Hejlsberg (ahejlsberg) May 30, 2018

Copy link
Copy Markdown
Member Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do, but with a few wrinkles. If the return type annotation includes void, any, or unknown we don't require any return statements. Otherwise, if the return type includes undefined we require at least one return statement somewhere, but don't require return statements to have expressions and allow the end point of the function to be reachable. Otherwise, we require a return statement with an expression at every exit point.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
mhegazy
Mohamed Hegazy (mhegazy) reviewed May 29, 2018
View reviewed changes
Comment thread tests/baselines/reference/conditionalTypes2.types
>T : T

boom: T extends any ? true : true
>boom : T extends any ? true : true

@mhegazy Mohamed Hegazy (mhegazy) May 29, 2018

Copy link
Copy Markdown
Contributor

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why did this type collapse to true?

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@ahejlsberg Anders Hejlsberg (ahejlsberg) May 29, 2018

Copy link
Copy Markdown
Member Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed this to eagerly resolve to true when the extends type is any or unknown (since it always will be).

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@weswigham Wesley Wigham (weswigham) May 29, 2018

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, but what about T extends any ? { x: T } : never - that needs to distribute.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@ahejlsberg Anders Hejlsberg (ahejlsberg) May 30, 2018

Copy link
Copy Markdown
Member Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, yes, I suppose we can only optimize when the conditional type isn't distributive.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@weswigham Wesley Wigham (weswigham) May 30, 2018 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a better check (than just distributivity) that I have an outstanding PR for: instantiate the check type (and infer types) in the true/false types with wildcards. If the instantiation isn't the input type, you can't simplify. If it is, you can. (Since the type isn't affected by instantiation)

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@AlCalzone AlCalzone mentioned this pull request Jul 17, 2018
Allow more constructs to work as type guards for unknown #25720
Open
4 tasks done
@Adjective-Object Max (Adjective-Object) mentioned this pull request Apr 24, 2019
Picker and Suggestions: Move the styled call out of render call. microsoft/fluentui#8834
Merged
2 tasks done
@ahejlsberg Anders Hejlsberg (ahejlsberg) mentioned this pull request Apr 30, 2019
False positive error report for enum and class instance type missing index signature, thus not assignable to object type with unknown values. #30977
Closed
@bdsl Barney Laurance (bdsl) mentioned this pull request Jun 3, 2019
Introduce top type vimeo/psalm#1729
Closed
@TinaHeiligers Christiane (Tina) Heiligers (TinaHeiligers) mentioned this pull request Sep 26, 2019
[lens] Use top nav in Lens app elastic/kibana#46190
Merged
@orta Orta Therox (orta) mentioned this pull request Oct 16, 2019
Well scoped PRs that added interesting features orta/typescript-notes#18
Open
@narumincho narumincho (narumincho) mentioned this pull request Jan 18, 2020
予約語などで変数名などを作らないようにする narumincho/js-ts-code-generator#9
Closed
@darh Denis Arh (darh) mentioned this pull request Feb 6, 2020
Feature helpers ts cortezaproject/corteza-js#1
Merged
4 tasks done
@fxlrnrpt Andrey Goncharov (fxlrnrpt) mentioned this pull request Jun 11, 2020
fix: runWithId should return the type of the function passed puzpuzpuz/cls-rtracer#33
Merged
@MartinJohns Martin Johns (MartinJohns) mentioned this pull request Jul 8, 2020
Consider making unknown a union of the object and all primitive types #39498
Closed
4 of 5 tasks
@stuft2 Spencer Tuft (stuft2) mentioned this pull request Aug 11, 2020
[fix] Update type declarations byuweb/byu-browser-oauth#12
Merged
@rekmarks Erik Marks (rekmarks) mentioned this pull request Feb 23, 2021
Add BaseControllerV2 state metadata MetaMask/core#362
Closed
Mark Stacey (Gudahtt) added a commit to MetaMask/core that referenced this pull request Feb 25, 2021
@Gudahtt
Use unknown rather than any for BaseController state
51c89d7
The BaseController state now uses `unknown` rather than `any` as the
type for state properties. `unknown` is more type-safe than `any` in
cases like this where we don't know what type to expect. See here for
details [1].

This was suggested by @rekmarks during review of #362 [2].

[1]: microsoft/TypeScript#24439
[2]: #362 (comment)
@Gudahtt Mark Stacey (Gudahtt) mentioned this pull request Feb 25, 2021
Use unknown rather than any for BaseController state MetaMask/core#365
Merged
Mark Stacey (Gudahtt) added a commit to MetaMask/core that referenced this pull request Feb 25, 2021
@Gudahtt
Use unknown rather than any for BaseController state (#365)
0d03fa4
* Use `unknown` rather than `any` for BaseController state

The BaseController state now uses `unknown` rather than `any` as the
type for state properties. `unknown` is more type-safe than `any` in
cases like this where we don't know what type to expect. See here for
details [1].

This was suggested by @rekmarks during review of #362 [2].

[1]: microsoft/TypeScript#24439
[2]: #362 (comment)

* Use type alias for controller state rather than interface

The mock controller state in the base controller tests now uses a type
alias for the controller state rather than an interface. This was
required to get around an incompatibility between
`Record<string, unknown>` and interfaces[1].

The `@typescript-eslint/consistent-type-definitions` ESLint rule has
been disabled, as this problem will be encountered fairly frequently.

[1]: microsoft/TypeScript#15300 (comment)
@IanMatthewHuff Ian Huff (IanMatthewHuff) mentioned this pull request Mar 16, 2021
Update for new NotebookCellOutput changes microsoft/vscode-notebook-renderers#35
Merged
@alexandre-lagadec-ost alexandre-lagadec-ost mentioned this pull request Oct 24, 2021
Ci/vood 48 use recommended linting rules ost-fh/Visual-OO-Debugger#9
Merged
@cmonti-bc Charly Monti (cmonti-bc) mentioned this pull request Feb 22, 2022
Feat(Tax Center) Tax Center page blockchain/blockchain-wallet-v4-frontend#4225
Merged
@erin-at-work erin-at-work mentioned this pull request Mar 25, 2022
Update window.ethereum type to unknown coinbase/coinbase-wallet-sdk#432
Merged
This was referenced Mar 10, 2023
Unknown types should be marked as unknown and not any adenh93/django-typomatic#29
Closed
Use unknown instead of any as the value to fallback to when the type is not known adenh93/django-typomatic#30
Merged
@rotu Dan Rose (rotu) mentioned this pull request Dec 31, 2023
Intersection, Union depends on type variable instantiation order #56906
Open
@AnnGreen1 用类生成对象 (AnnGreen1) mentioned this pull request Feb 24, 2024
TypeScript 3.0: unknown 类型 AnnGreen1/article#13
Open
@AnnGreen1 用类生成对象 (AnnGreen1) mentioned this pull request Mar 11, 2024
[译] TypeScript 3.0 unknown 类型 AnnGreen1/article#18
Open
@EltonLobo07 Elton Lobo (EltonLobo07) mentioned this pull request Apr 21, 2024
_addIssue blocks every, some & check actions rewrite due to a possible type issue open-circle/valibot#540
Closed
@echappen echappen mentioned this pull request Apr 22, 2024
Jvd/orgs cloud-gov/cg-ui#141
Merged
@bakar-io Bakar Tavadze (bakar-io) mentioned this pull request May 8, 2024
Deleting assistants & attaching orphaned threads to new assistants langchain-ai/opengpts#328
Merged
@microsoft Microsoft (microsoft) locked as resolved and limited conversation to collaborators Oct 21, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Reviewers

@weswigham Wesley Wigham (weswigham) weswigham left review comments
@DanielRosenwasser Daniel Rosenwasser (DanielRosenwasser) Awaiting requested review from DanielRosenwasser
+1 more reviewer
@mhegazy Mohamed Hegazy (mhegazy) mhegazy approved these changes
Reviewers whose approvals may not affect merge requirements

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

10 participants

@ahejlsberg @RyanCavanaugh @weswigham @Retsam @c69 @Yogu @MadaraUchiha @mhegazy @wesleyolis @jean-pasqualini
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.