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 — Allow dynamic names in types by rbuckton · Pull Request #15473 · microsoft/TypeScript

Conversation

@rbuckton

@rbuckton Ron Buckton (rbuckton) commented Apr 29, 2017 •
edited
Loading

Uh oh!

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

Copy link
Copy Markdown
Contributor

This changes allows the use of an Identifier or PropertyAccessExpression as part of a computed property name in an interface, class, or type literal as long as the type of the expression is a string or numeric literal type, or is a unique symbol type.

Unique Symbol Types

A unique symbol type is created in specific cases when calling the global Symbol function or the global Symbol.for function, or when you use the unique symbol type.

Unique symbol types have several rules and restrictions:

  • The unique symbol type may only be used on a const variable or readonly property declaration.
  • The unique symbol type widens to symbol.
  • Two unique symbol types are not assignable to each other.
  • A unique symbol type is bound to the symbol of the declaration where it was defined.
    • This prevents assignability errors when merging declarations of the same variable/property that both define their type as unique symbol, as the names for these declarations merge into the same symbol.
  • NOTE: Even though Symbol.for(x) would return the same ES Symbol at runtime if called multiple times for the same x, we currently treat separate calls to Symbol.for(x) as unique symbols. We may choose to revisit this in the future.

Examples

// main.ts (input)
const x = Symbol();
const y = x;
const z: typeof x = x;
interface SymbolConstructor {
  readonly iterator: unique symbol; 
}
interface SymbolConstructor {
  readonly iterator: unique symbol; // ok
}

// main.d.ts (declaration output)
const x: unique symbol;
const y: symbol;
const z: typeof x;
interface SymbolConstructor {
  readonly iterator: unique symbol; 
}
interface SymbolConstructor {
  readonly iterator: unique symbol;
}

Late Binding

Dynamic member names are resolved and "bound" in the checker on-demand whenever the members of a symbol are requested, allowing members with dynamic names to participate in type relationships.

Since dynamic members are bound later than syntactically recognizable member names, we disallow defining a member both syntactically and via a dynamic name so as not to introduce inconsistencies with overload resolution as the declarations might end up in the wrong order.

Examples

// main.ts (input)
export const x = "literal name";
const y = 1;
export interface A {
  [x]: string;
  [y]: string; // error: Interface 'A' has or is using private name '[y]' (when using --declaration)
}
type B {
  [x]: string;
  [y]: boolean;
}
let a: A;
let b: B;
a = b; // error: Type 'B' is not assignable to type 'A'. Types of property '[y]' are incompatible.

// main.d.ts (declaration output)
export declare const x = "literal name";
export interface A { 
  [x]: string; 
}

Fixes #2012
Fixes #5579
Fixes #7436 (via typeof SAYHELLO)
Fixes #11736 (via typeof opAdd)
Partially Fixes #13031 (via unique symbol type, though there are other issues that still block this)

Sorry, something went wrong.

Uh oh!

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

alitaheri, dmichon-msft, basarat, xiaoyudesu, weswigham, yortus, farism, pocesar, aluanhaddad, zheeeng, and 40 more reacted with thumbs up emoji alitaheri, svieira, xiaoyudesu, Jessidhia, farism, begincalendar, olaf89, steve8708, axefrog, TylorS, and 10 more reacted with hooray emoji alitaheri, xiaoyudesu, Jessidhia, blakeembrey, shlomiborovitz, steve8708, TylorS, axefrog, vitaly-t, gcnew, and 4 more reacted with heart emoji
All reactions
  • 👍 50 reactions
  • 🎉 20 reactions
  • ❤️ 14 reactions
@rbuckton
Allow some dynamic names in types
d8cb3c6
@msftclas Microsoft Contribution License Agreements (msftclas) added the cla-not-required label Apr 29, 2017
@rbuckton
Add support for declaration emit
0c1eef7
@rbuckton
Ron Buckton (rbuckton) requested review from Anders Hejlsberg (ahejlsberg), Mohamed Hegazy (mhegazy) and Nathan Shively-Sanders (sandersn) April 29, 2017 22:18
gcnew
Marin Marinov (gcnew) reviewed Apr 29, 2017
View reviewed changes
Comment thread tests/cases/compiler/dynamicNames.ts Outdated

interface T16 {
[c5]: number;
[c6]: string;

@gcnew Marin Marinov (gcnew) Apr 29, 2017 •
edited
Loading

Uh oh!

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

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.

Shouldn't this be an error? I also tested with duplicate string literals with incompatible types. I expected a compile time error, however a union may also be possible.

const k1 = "literal name";
const k2 = "literal name";

interface T17 {
  [k1]: string;
  [k2]: 123;  // error expected
}

type T18 = {
  [k1]: string;
  [k2]: 123;  // error expected
}

// strange IntelliSense:
// type T18 = { literal name: string }

interface T19 {
  ['literal name']: string;
  ['literal name']: 123; // error as expected
}

interface T20 {
  ['literal name']: string; // error here
  [k1]: 123;                // and also here
}

let t17: T17;
t17['literal name'] // strange IntelliSense: `T17.literal name: string`

let t19: T19;
t19['literal name'] // strange IntelliSense: `T19[['literal name']]: string`

Sorry, something went wrong.

Uh oh!

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

All reactions
@rbuckton
Report errors from duplicate member names
d572a54
@sandersn

Nathan Shively-Sanders (sandersn) commented May 2, 2017

Copy link
Copy Markdown
Member

Can you give an example of the symbol literal type scenario?

All reactions

Sorry, something went wrong.

Uh oh!

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

sandersn
Nathan Shively-Sanders (sandersn) requested changes May 2, 2017
View reviewed changes

@sandersn Nathan Shively-Sanders (sandersn) left a comment

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.

The code looks solid enough, but I don't really get why this change is needed right now. It seems like a lot of change without much payoff. Maybe this should wait until we have symbol literal types?

Also a few nitpicks in the comments.

Sorry, something went wrong.

Uh oh!

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

All reactions
Comment thread tests/cases/compiler/dynamicNames.ts
@@ -0,0 +1,102 @@
// @target: esnext
// @module: commonjs
// @filename: module.ts

@sandersn Nathan Shively-Sanders (sandersn) May 2, 2017

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.

can you add // @declaration: true here to test the declarationEmitter code?

Sorry, something went wrong.

Uh oh!

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

All reactions
Comment thread src/compiler/checker.ts Outdated
if (name) {
// TODO(rbuckton): ESSymbolLiteral
const nameType = checkComputedPropertyName(name);
return (nameType.flags & TypeFlags.StringOrNumberLiteral) !== 0;

@sandersn Nathan Shively-Sanders (sandersn) May 2, 2017

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 personally find !! easier to read than !== 0, but I'm not sure how common that is..

Sorry, something went wrong.

Uh oh!

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

All reactions

@rbuckton Ron Buckton (rbuckton) May 2, 2017

Copy link
Copy Markdown
Contributor 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'm not sure it has a major impact on performance, but !! requires coercion from SMI to boolean, while !== 0 does not.

Sorry, something went wrong.

Uh oh!

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

All reactions
Comment thread src/compiler/checker.ts Outdated
}

function resolveDynamicMembersOfClassOrInterfaceOrTypeLiteralNode(node: ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode, symbolTable: SymbolTable) {
for (const member of node.members) {

@sandersn Nathan Shively-Sanders (sandersn) May 2, 2017

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.

it would be simpler to have a third parameter symbol and only one resolveDynamicMembersOfNode(members: NodeArray<ClassElement | TypeElement | ObjectLiteralElementLike>, symbols: Symbol[], symbolTable: SymbolTable). Then resolveDynamicMembersOfSymbol could pull off the properties of node in each case.

Sorry, something went wrong.

Uh oh!

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

All reactions
@rbuckton

Ron Buckton (rbuckton) commented May 2, 2017 •
edited
Loading

Uh oh!

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

Copy link
Copy Markdown
Contributor Author

Nathan Shively-Sanders (@sandersn) Symbol literal types are a whole other complicated issue. This is basically a rough-in for where symbol literal types would be used, but at least gives us the ability to use string and numeric literal types for dynamic property names now. The branch I am working on that has symbol literal types builds on this, and will help keep the scope of a future PR to just symbol literal specific functionality.

The PR has been updated to include unique symbol types.

All reactions

Sorry, something went wrong.

Uh oh!

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

Ron Buckton (rbuckton) and others added 8 commits May 2, 2017 16:22
@rbuckton
Add declaration file output to tests
2714295
@rbuckton
Merge branch 'master' into dynamicNames
3181a8d
@rbuckton
Accept baselines
b5f1169
@rbuckton
PR feedback
3b684d4
@rbuckton
fix symbol display for computed properties
64fd857
@rbuckton
Early support for unique symbol type
d8ae9c0
@rbuckton
Add freshness to unique symbol types
83b5a75
@rbuckton
Emit dynamic names for object literal types
57674dd
@rbuckton
Ron Buckton (rbuckton) force-pushed the dynamicNames branch from 255ff27 to 57674dd Compare May 5, 2017 17:54
Ron Buckton (rbuckton) added 3 commits May 5, 2017 11:05
@rbuckton
Merge branch 'dynamicNames' into symbolLiterals
fc61863
@rbuckton
Ensure we get the correct symbol for nodes, clean up
fe414a2
@rbuckton
Improve union type reduction for symbol()
93ea56b
@rbuckton

Ron Buckton (rbuckton) commented May 6, 2017

Copy link
Copy Markdown
Contributor Author

Updated with support for unique symbol types. Also updated the description, above.

All reactions

Sorry, something went wrong.

Uh oh!

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

@rbuckton

Ron Buckton (rbuckton) commented May 6, 2017

Copy link
Copy Markdown
Contributor Author

At some point we may choose to simplify the binder with respect to well-known symbols and let late-binding take care of it.

All reactions

Sorry, something went wrong.

Uh oh!

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

Ron Buckton (rbuckton) added 4 commits May 10, 2017 09:40
@rbuckton
Merge branch 'master' into dynamicNames
2a73d08
@rbuckton
Merge branch 'master' into dynamicNames
625b37e
@rbuckton
Merge branch 'master' into dynamicNames
8c3b73f
@rbuckton
Merge branch 'master' into dynamicNames
c4e9ce5
@rbuckton

Ron Buckton (rbuckton) commented Jun 7, 2017

Copy link
Copy Markdown
Contributor Author

Nathan Shively-Sanders (@sandersn) any other comments?

All reactions

Sorry, something went wrong.

Uh oh!

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

Ron Buckton (rbuckton) added 3 commits November 10, 2017 14:42
@rbuckton
Simplify literal/unique symbol widening
b9dbf5d
@rbuckton
Fix getReturnTypeFromBody widening
ae11ae5
@rbuckton
Merge branch 'master' into dynamicNames
804c7d3
@rbuckton

Ron Buckton (rbuckton) commented Nov 13, 2017

Copy link
Copy Markdown
Contributor Author

Anders Hejlsberg (@ahejlsberg), Mohamed Hegazy (@mhegazy): In ae11ae5 I've made some changes to how we handle widening in getReturnTypeFromBody to address widening of unique symbol types. This changes how we resolve the return types for async functions, async generators, and generators where it seems like we weren't sufficiently widening literal types in these cases like we were for normal functions. This could be considered a breaking change, so I'd like to know if this is acceptable. If not I can revert to the old behavior, but this seems more consistent.

All reactions

Sorry, something went wrong.

Uh oh!

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

@DanielRosenwasser Daniel Rosenwasser (DanielRosenwasser) mentioned this pull request Nov 15, 2017
Spec needs to account for computed constant names #20058
Closed
2 tasks
Ron Buckton (rbuckton) added 2 commits November 15, 2017 15:24
@rbuckton
Merge branch 'master' into dynamicNames
a21a129
@rbuckton
PR feedback
86b0759
ahejlsberg
Anders Hejlsberg (ahejlsberg) approved these changes Nov 16, 2017
View reviewed changes
Ron Buckton (rbuckton) added 2 commits November 15, 2017 17:12
@rbuckton
Use correct base primitive type
0b24f02
@rbuckton
Use correct base primitive type
ccba128
@rbuckton
Ron Buckton (rbuckton) merged commit b4ea700 into master Nov 16, 2017
@rbuckton
Ron Buckton (rbuckton) deleted the dynamicNames branch November 16, 2017 03:14
@weswigham Wesley Wigham (weswigham) mentioned this pull request Nov 16, 2017
Enum member used in computed property name leads to compile error when using outputted .d.ts file #19704
Closed
@yortus Troy Gerwien (yortus) mentioned this pull request Nov 20, 2017
Property '[mySymbol]' is not assignable to string index type #20146
Closed
@nisimjoseph

Nisim Joseph (nisimjoseph) commented Dec 6, 2017

Copy link
Copy Markdown

can I use without use "// ts-ignore" instruction to make the compiler ignore that "mistake"?

for example:

interface HandlerHash
{
    [eventType:string | symbol]:Function[];
}

All reactions

Sorry, something went wrong.

Uh oh!

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

@phiresky phiresky mentioned this pull request Dec 7, 2017
Support some non-structural (nominal) type matching #202
Open
@yortus Troy Gerwien (yortus) mentioned this pull request Dec 15, 2017
Consider adding symbolof type operator, like keyof but for unique symbol properties #20721
Closed
@DanielRosenwasser Daniel Rosenwasser (DanielRosenwasser) mentioned this pull request Dec 22, 2017
Can't infer param type of method assigned to computed property name using string enum value #20856
Closed
This was referenced Dec 26, 2017
TypeScript 2.7: exclamation marks in property declarations aren't parsed prettier/prettier#3561
Closed
TypeScript 2.7: unique symbol type isn't parsed prettier/prettier#3577
Closed
@ikatyang Ika (ikatyang) mentioned this pull request Dec 26, 2017
Support unique symbol type (TS 2.7) eslint/typescript-eslint-parser#426
Closed
@rozzzly Patrick Lienau (rozzzly) mentioned this pull request Dec 26, 2017
Allow unique symbols to be interchangeable with types. Also assignability bug with Symbol(). #20898
Closed
@strax Sami Kukkonen (strax) mentioned this pull request Dec 31, 2017
Use Symbol.species? gcanti/fp-ts#156
Closed
@ghost ghost mentioned this pull request Jan 18, 2018
TypeScript: Support parsing 'unique' type operator babel/babel#7239
Merged
@HerringtonDarkholme

Herrington Darkholme (HerringtonDarkholme) commented Jan 22, 2018

Copy link
Copy Markdown
Contributor

Daniel Rosenwasser (@DanielRosenwasser) unique symbol is a notable feature in TS2.7 and it can benefit terminal users a lot, e.g., Angular's NgOnInit interface can use this to avoid method name conflict.

Can we add it to What's new in TypeScript wiki? Indeed sometimes TS' new awesome features are more than one can follow. 😜

kgtkr and caseyWebb reacted with thumbs up emoji
All reactions
  • 👍 2 reactions

Sorry, something went wrong.

Uh oh!

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

@mhegazy

Mohamed Hegazy (mhegazy) commented Jan 24, 2018

Copy link
Copy Markdown
Contributor

Herrington Darkholme (@HerringtonDarkholme) we are updating the docs currently. we should have them all up-to-date before the final 2.7 goes out next week.

kgtkr reacted with hooray emoji
All reactions
  • 🎉 1 reaction

Sorry, something went wrong.

Uh oh!

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

@ghost ghost mentioned this pull request Feb 22, 2018
isDeclarationName: support ComputedPropertyName #22123
Merged
@ghost ghost mentioned this pull request Mar 3, 2018
How to handle this when this is a function #22285
Closed
@ahejlsberg Anders Hejlsberg (ahejlsberg) mentioned this pull request Apr 20, 2018
Support number and symbol named properties with keyof and mapped types #23592
Merged
@microsoft Microsoft (microsoft) locked and limited conversation to collaborators Jul 3, 2018
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
@sandersn Nathan Shively-Sanders (sandersn) sandersn approved these changes
@ahejlsberg Anders Hejlsberg (ahejlsberg) ahejlsberg approved these changes
@mhegazy Mohamed Hegazy (mhegazy) Awaiting requested review from mhegazy
+1 more reviewer
@gcnew Marin Marinov (gcnew) gcnew left review comments
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.

Proposal: a literal notation for well-known symbols Better typing support for ES2015 symbols Symbols as literal types Support type-checking of computed properties for constants and Symbols Challenges with ES6 symbols

Uh oh!

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

12 participants

@rbuckton @sandersn @pocesar @falsandtru @weswigham @ahejlsberg @nisimjoseph @HerringtonDarkholme @mhegazy @gcnew @msftclas @msftgits
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.