Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

New 'unknown' top type#24439

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
ahejlsberg merged 25 commits intomasterfromunknownType
May 30, 2018
Merged

New 'unknown' top type#24439

ahejlsberg merged 25 commits intomasterfromunknownType
May 30, 2018

Conversation

@ahejlsberg
Copy link
Member

@ahejlsbergahejlsberg commentedMay 27, 2018
edited
Loading

This PR adds a new top typeunknown which is the type-safe counterpart ofany. Anything is assignable tounknown, butunknown isn't assignable to anything but itself andany without a type assertion or a control flow based narrowing. Likewise, no operations are permitted on anunknown without first asserting or narrowing to a more specific type.

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

// In an intersection everything absorbs unknowntypeT00=unknown&null;// nulltypeT01=unknown&undefined;// undefinedtypeT02=unknown&null&undefined;// null & undefined (which becomes never in union)typeT03=unknown&string;// stringtypeT04=unknown&string[];// string[]typeT05=unknown&unknown;// unknowntypeT06=unknown&any;// any// In a union an unknown absorbs everythingtypeT10=unknown|null;// unknowntypeT11=unknown|undefined;// unknowntypeT12=unknown|null|undefined;// unknowntypeT13=unknown|string;// unknowntypeT14=unknown|string[];// unknowntypeT15=unknown|unknown;// unknowntypeT16=unknown|any;// any// Type variable and unknown in union and intersectiontypeT20<T>=T&{};// T & {}typeT21<T>=T|{};// T | {}typeT22<T>=T&unknown;// TtypeT23<T>=T|unknown;// unknown// unknown in conditional typestypeT30<T>=unknownextendsT ?true :false;// DeferredtypeT31<T>=Textendsunknown ?true :false;// Deferred (so it distributes)typeT32<T>=neverextendsT ?true :false;// truetypeT33<T>=Textendsnever ?true :false;// Deferred// keyof unknowntypeT40=keyofany;// string | number | symboltypeT41=keyofunknown;// never// Only equality operators are allowed with unknownfunctionf10(x:unknown){x==5;x!==10;x>=0;// Errorx+1;// Errorx*2;// Error-x;// Error+x;// Error}// No property accesses, element accesses, or function callsfunctionf11(x:unknown){x.foo;// Errorx[5];// Errorx();// Errornewx();// Error}// typeof, instanceof, and user defined type predicatesdeclarefunctionisFunction(x:unknown):x isFunction;functionf20(x:unknown){if(typeofx==="string"||typeofx==="number"){x;// string | number}if(xinstanceofError){x;// Error}if(isFunction(x)){x;// Function}}// Homomorphic mapped type over unknowntypeT50<T>={[PinkeyofT]:number};typeT51=T50<any>;// { [x: string]: number }typeT52=T50<unknown>;// {}// Anything is assignable to unknownfunctionf21<T>(pAny:any,pNever:never,pT:T){letx:unknown;x=123;x="hello";x=[1,2,3];x=newError();x=x;x=pAny;x=pNever;x=pT;}// unknown assignable only to itself and anyfunctionf22(x:unknown){letv1:any=x;letv2:unknown=x;letv3:object=x;// Errorletv4:string=x;// Errorletv5:string[]=x;// Errorletv6:{}=x;// Errorletv7:{}|null|undefined=x;// Error}// Type parameter 'T extends unknown' not related to objectfunctionf23<Textendsunknown>(x:T){lety:object=x;// Error}// Anything but primitive assignable to { [x: string]: unknown }functionf24(x:{[x:string]:unknown}){x={};x={a:5};x=[1,2,3];x=123;// Error}// Locals of type unknown always considered initializedfunctionf25(){letx:unknown;lety=x;}// Spread of unknown causes result to be unknownfunctionf26(x:{},y:unknown,z:any){leto1={a:42, ...x};// { a: number }leto2={a:42, ...x, ...y};// unknownleto3={a:42, ...x, ...y, ...z};// any}// Functions with unknown return type don't need return expressionsfunctionf27():unknown{}// Rest type cannot be created from unknownfunctionf28(x:unknown){let{ ...a}=x;// Error}// Class properties of type unknown don't need definite assignmentclassC1{a:string;// Errorb:unknown;c:any;}

Fixes#10715.

alexrock, yortus, Kingwl, j-oliveras, ajafff, Jessidhia, ericanderson, zpdDG4gta8XKpMCd, krryan, ahagelstein, and 146 more reacted with thumbs up emojialfaproject, yortus, Kingwl, j-oliveras, svieira, Jessidhia, ericanderson, zpdDG4gta8XKpMCd, krryan, pelotom, and 48 more reacted with hooray emojiyortus, Kingwl, j-oliveras, zpdDG4gta8XKpMCd, krryan, Ebuall, ibezkrovnyi, andrew-morris-orbis, alcuadrado, mohsen1, and 49 more reacted with heart emoji
@ahejlsbergahejlsberg changed the titleNew 'unknownNew 'unknown' top typeMay 27, 2018
@RyanCavanaugh
Copy link
Member

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

@weswigham
Copy link
Member

weswigham commentedMay 29, 2018
edited
Loading

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

Does that make sense (is this derived from something else)? Ifunknown 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 isnever (the given types seem correct fornever, this being a place whereany is more never-like than top-like).

glentakahashi reacted with thumbs up emoji

@ahejlsberg
Copy link
MemberAuthor

@weswigham No, that probably doesn't make sense. We should be similar tokeyof {} andkeyof object here, both of which arenever.

@ahejlsberg
Copy link
MemberAuthor

@RyanCavanaugh Do you mean the behavior ofunknown 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


// 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)) {
Copy link
Member

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 explicitunknown should probably have return values? Otherwise you should've writtenvoid orundefined, right?

mhegazy, gcnew, and melissab1238 reacted with thumbs up emoji
Copy link
MemberAuthor

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 ofunknown (just like it is in the domain ofany) and that's really what should guide us here.

Copy link
Member

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 withundefined in accordance with that, then?

Copy link
MemberAuthor

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 includesvoid,any, orunknown we don't requireanyreturn statements. Otherwise, if the return type includesundefined we require at least onereturn statement somewhere, but don't requirereturn statements to have expressions and allow the end point of the function to be reachable. Otherwise, we require areturn statement with an expression at every exit point.

>T : T

boom: T extends any ? true : true
>boom :T extends any ? true :true
Copy link
Contributor

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 totrue?

Copy link
MemberAuthor

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 totrue when the extends type isany orunknown (since it always will be).

Copy link
Member

Choose a reason for hiding this comment

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

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

Copy link
MemberAuthor

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.

Copy link
Member

@weswighamweswighamMay 30, 2018
edited
Loading

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)

@bdslbdsl mentioned this pull requestJun 3, 2019
@darhdarh mentioned this pull requestFeb 6, 2020
4 tasks
Gudahtt added a commit to MetaMask/core that referenced this pull requestFeb 25, 2021
The BaseController state now uses `unknown` rather than `any` as thetype for state properties. `unknown` is more type-safe than `any` incases like this where we don't know what type to expect. See here fordetails [1].This was suggested by@rekmarks during review of#362 [2].[1]:microsoft/TypeScript#24439[2]:#362 (comment)
Gudahtt added a commit to MetaMask/core that referenced this pull requestFeb 25, 2021
* Use `unknown` rather than `any` for BaseController stateThe BaseController state now uses `unknown` rather than `any` as thetype for state properties. `unknown` is more type-safe than `any` incases like this where we don't know what type to expect. See here fordetails [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 interfaceThe mock controller state in the base controller tests now uses a typealias for the controller state rather than an interface. This wasrequired to get around an incompatibility between`Record<string, unknown>` and interfaces[1].The `@typescript-eslint/consistent-type-definitions` ESLint rule hasbeen disabled, as this problem will be encountered fairly frequently.[1]:microsoft/TypeScript#15300 (comment)
MajorLift pushed a commit to MetaMask/core that referenced this pull requestOct 11, 2023
* Use `unknown` rather than `any` for BaseController stateThe BaseController state now uses `unknown` rather than `any` as thetype for state properties. `unknown` is more type-safe than `any` incases like this where we don't know what type to expect. See here fordetails [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 interfaceThe mock controller state in the base controller tests now uses a typealias for the controller state rather than an interface. This wasrequired to get around an incompatibility between`Record<string, unknown>` and interfaces[1].The `@typescript-eslint/consistent-type-definitions` ESLint rule hasbeen disabled, as this problem will be encountered fairly frequently.[1]:microsoft/TypeScript#15300 (comment)
MajorLift pushed a commit to MetaMask/core that referenced this pull requestOct 11, 2023
* Use `unknown` rather than `any` for BaseController stateThe BaseController state now uses `unknown` rather than `any` as thetype for state properties. `unknown` is more type-safe than `any` incases like this where we don't know what type to expect. See here fordetails [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 interfaceThe mock controller state in the base controller tests now uses a typealias for the controller state rather than an interface. This wasrequired to get around an incompatibility between`Record<string, unknown>` and interfaces[1].The `@typescript-eslint/consistent-type-definitions` ESLint rule hasbeen disabled, as this problem will be encountered fairly frequently.[1]:microsoft/TypeScript#15300 (comment)
@echappenechappen mentioned this pull requestApr 22, 2024
@microsoftmicrosoft locked asresolvedand limited conversation to collaboratorsOct 21, 2025
Sign up for freeto subscribe to this conversation on GitHub. Already have an account?Sign in.

Reviewers

@weswighamweswighamweswigham left review comments

@DanielRosenwasserDanielRosenwasserAwaiting requested review from DanielRosenwasser

+1 more reviewer

@mhegazymhegazymhegazy approved these changes

Reviewers whose approvals may not affect merge requirements

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

11 participants

@ahejlsberg@RyanCavanaugh@weswigham@Retsam@c69@Yogu@MadaraUchiha@mhegazy@wesleyolis@jean-pasqualini

[8]ページ先頭

©2009-2025 Movatter.jp