Defer indexed access T[K] with non-generic K - #12770

Merged
Anders Hejlsberg (ahejlsberg) merged 6 commits into
masterfrom
deferIndexedAccess
Dec 10, 2016
Merged

Defer indexed access T[K] with non-generic K#12770
Anders Hejlsberg (ahejlsberg) merged 6 commits into
masterfrom
deferIndexedAccess

Conversation

@ahejlsberg

@ahejlsbergAnders Hejlsberg (ahejlsberg) commented Dec 8, 2016

Copy link
Copy Markdown
Member

With this PR we defer resolution of indexed access types T[K] where T is generic and K is non-generic.

functiongetValue<Textends{value: string|number}>(obj: T): T['value']{returnobj.value;}letx1=getValue({value: 'hello'});// stringletx2=getValue({value: 42});// number

In the example above, the indexed access type T['value'] is permitted because T is constrained to a type that has a property named value. The type T['value'] behaves like a subtype of string | number because that is the type of value in the constraint type, and when instantiation substitutes an actual type for T, the type of the value property in that actual type is substituted for T['value'].

Note that for backwards compatibility reasons, the expression obj.value is still eagerly resolved to type string | number. The expression must be explicitly coerced to T['value'] using a type annotation or a type assertion in order to get the deferred behavior.

This PR also implements better circularity detection and reporting for indexed access types. For example:

typeT1={x: T1['x'];// Error};

Note that circularities may sometimes result only for certain arguments to type parameters.

typeT2<Kextends'x'|'y'>={x: T2<K>[K];// Errory: number;}declareletobj: T2<'x'>;letx=obj.x;

If the type of obj above is changed to T2<'y'> the circularity error goes away.

Fixes#12651.
Fixes#12723.
Fixes#12744.

# Conflicts:
#	src/compiler/checker.ts
#	tests/baselines/reference/keyofAndIndexedAccess.js
#	tests/baselines/reference/keyofAndIndexedAccess.symbols
#	tests/baselines/reference/keyofAndIndexedAccess.types
#	tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts
@eschwartz

Copy link
Copy Markdown

I just want to point out that once this is fixed, we should be able to implement a better EventEmitter definition, with typed events.

For example

// Encapulate an event's name and datainterfaceEventType<TNameextendsstring,TDataextendsany>{name: TName;data: TData;}classEventEmitter<TEventTypeextendsEventType<string,any>>{on<TTypeextendsTEventType>(name: TType["name"],listener:(event: TType["data"])=>void):this;/*...*/}

Usage:

typeEventTypeA=EventType<'a',{foo: string;}>;typeEventTypeB=EventType<'b',{bar: string;}>;constemitter=newEventEmitter<EventTypeA|EventTypeB>();// emitter.on requires that the event name and data match the provided EventTypeemitter.on<EventTypeA>('a',(evt)=>{evt.foo;});emitter.on(EventTypeB>('b',(evt)=>{evt.bar;});

@eschwartz

Copy link
Copy Markdown

Any idea when this might be released? Should we be expecting a 2.1.5 to come out soon with this fix?

(also, thanks for all the work on this. This is really cool stuff, and I'm having a ton of fun using it)

@rotemdan

Rotem Dan (rotemdan) commented Dec 10, 2016

Copy link
Copy Markdown

I believe I've found an alternative, though less elegant, approach to my dispatcher example that doesn't rely on discriminated unions and might work with the new inference capability described here without any need for additional syntax:

typeDispatcherSchema={[name: string]: {argTypes: any[];returnType: any}};classDispatcher<SextendsDispatcherSchema>{dispatch<KextendskeyofS>(name: K,args: S[K]['argTypes']): S[K]['returnType']{// ...}}typeMySchema={"read": {argTypes: [string,number];returnType: string[];};"write": {argTypes: [string,string[],boolean];returnType: number;};}constdispatcher=newDispatcher<MySchema>();varresult=dispatcher.dispatch("read",["myfile.txt",35]);// okvarresult=dispatcher.dispatch("read","myfile.txt");// already errorsvarresult=dispatcher.dispatch("reed",["myfile.txt",35]);// already errorsvarresult=dispatcher.dispatch("write",["myfile.txt","oops",true]);// might error with this PR?

It seems promising but I have not tested this yet though (I'm waiting for the pull request to be merged and arrive to the nightly builds).

(If this does prove to work I'll probably start applying this pattern literally immediately in my code...)

@eschwartz

Copy link
Copy Markdown

Just downloaded typescript@2.2.0-dev.20161212, and my EventEmitter example is working great 👍

@eschwartz

Copy link
Copy Markdown

Any chance this can make it into 2.1.5?

@microsoftMicrosoft (microsoft) locked and limited conversation to collaborators Jun 19, 2018
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

5 participants

@ahejlsberg@eschwartz@rotemdan@mhegazy@msftclas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Defer indexed access T[K] with non-generic K - #12770

Merged
Anders Hejlsberg (ahejlsberg) merged 6 commits into
masterfrom
deferIndexedAccess
Dec 10, 2016
Merged

Defer indexed access T[K] with non-generic K#12770
Anders Hejlsberg (ahejlsberg) merged 6 commits into
masterfrom
deferIndexedAccess

Conversation

@ahejlsberg

@ahejlsbergAnders Hejlsberg (ahejlsberg) commented Dec 8, 2016

Copy link
Copy Markdown
Member

With this PR we defer resolution of indexed access types T[K] where T is generic and K is non-generic.

functiongetValue<Textends{value: string|number}>(obj: T): T['value']{returnobj.value;}letx1=getValue({value: 'hello'});// stringletx2=getValue({value: 42});// number

In the example above, the indexed access type T['value'] is permitted because T is constrained to a type that has a property named value. The type T['value'] behaves like a subtype of string | number because that is the type of value in the constraint type, and when instantiation substitutes an actual type for T, the type of the value property in that actual type is substituted for T['value'].

Note that for backwards compatibility reasons, the expression obj.value is still eagerly resolved to type string | number. The expression must be explicitly coerced to T['value'] using a type annotation or a type assertion in order to get the deferred behavior.

This PR also implements better circularity detection and reporting for indexed access types. For example:

typeT1={x: T1['x'];// Error};

Note that circularities may sometimes result only for certain arguments to type parameters.

typeT2<Kextends'x'|'y'>={x: T2<K>[K];// Errory: number;}declareletobj: T2<'x'>;letx=obj.x;

If the type of obj above is changed to T2<'y'> the circularity error goes away.

Fixes#12651.
Fixes#12723.
Fixes#12744.

# Conflicts:
#	src/compiler/checker.ts
#	tests/baselines/reference/keyofAndIndexedAccess.js
#	tests/baselines/reference/keyofAndIndexedAccess.symbols
#	tests/baselines/reference/keyofAndIndexedAccess.types
#	tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts
@eschwartz

Copy link
Copy Markdown

I just want to point out that once this is fixed, we should be able to implement a better EventEmitter definition, with typed events.

For example

// Encapulate an event's name and datainterfaceEventType<TNameextendsstring,TDataextendsany>{name: TName;data: TData;}classEventEmitter<TEventTypeextendsEventType<string,any>>{on<TTypeextendsTEventType>(name: TType["name"],listener:(event: TType["data"])=>void):this;/*...*/}

Usage:

typeEventTypeA=EventType<'a',{foo: string;}>;typeEventTypeB=EventType<'b',{bar: string;}>;constemitter=newEventEmitter<EventTypeA|EventTypeB>();// emitter.on requires that the event name and data match the provided EventTypeemitter.on<EventTypeA>('a',(evt)=>{evt.foo;});emitter.on(EventTypeB>('b',(evt)=>{evt.bar;});

@eschwartz

Copy link
Copy Markdown

Any idea when this might be released? Should we be expecting a 2.1.5 to come out soon with this fix?

(also, thanks for all the work on this. This is really cool stuff, and I'm having a ton of fun using it)

@rotemdan

Rotem Dan (rotemdan) commented Dec 10, 2016

Copy link
Copy Markdown

I believe I've found an alternative, though less elegant, approach to my dispatcher example that doesn't rely on discriminated unions and might work with the new inference capability described here without any need for additional syntax:

typeDispatcherSchema={[name: string]: {argTypes: any[];returnType: any}};classDispatcher<SextendsDispatcherSchema>{dispatch<KextendskeyofS>(name: K,args: S[K]['argTypes']): S[K]['returnType']{// ...}}typeMySchema={"read": {argTypes: [string,number];returnType: string[];};"write": {argTypes: [string,string[],boolean];returnType: number;};}constdispatcher=newDispatcher<MySchema>();varresult=dispatcher.dispatch("read",["myfile.txt",35]);// okvarresult=dispatcher.dispatch("read","myfile.txt");// already errorsvarresult=dispatcher.dispatch("reed",["myfile.txt",35]);// already errorsvarresult=dispatcher.dispatch("write",["myfile.txt","oops",true]);// might error with this PR?

It seems promising but I have not tested this yet though (I'm waiting for the pull request to be merged and arrive to the nightly builds).

(If this does prove to work I'll probably start applying this pattern literally immediately in my code...)

@eschwartz

Copy link
Copy Markdown

Just downloaded typescript@2.2.0-dev.20161212, and my EventEmitter example is working great 👍

@eschwartz

Copy link
Copy Markdown

Any chance this can make it into 2.1.5?

@microsoftMicrosoft (microsoft) locked and limited conversation to collaborators Jun 19, 2018
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

5 participants

@ahejlsberg@eschwartz@rotemdan@mhegazy@msftclas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Defer indexed access T[K] with non-generic K - #12770

Merged
Anders Hejlsberg (ahejlsberg) merged 6 commits into
masterfrom
deferIndexedAccess
Dec 10, 2016
Merged

Defer indexed access T[K] with non-generic K#12770
Anders Hejlsberg (ahejlsberg) merged 6 commits into
masterfrom
deferIndexedAccess

Conversation

@ahejlsberg

@ahejlsbergAnders Hejlsberg (ahejlsberg) commented Dec 8, 2016

Copy link
Copy Markdown
Member

With this PR we defer resolution of indexed access types T[K] where T is generic and K is non-generic.

functiongetValue<Textends{value: string|number}>(obj: T): T['value']{returnobj.value;}letx1=getValue({value: 'hello'});// stringletx2=getValue({value: 42});// number

In the example above, the indexed access type T['value'] is permitted because T is constrained to a type that has a property named value. The type T['value'] behaves like a subtype of string | number because that is the type of value in the constraint type, and when instantiation substitutes an actual type for T, the type of the value property in that actual type is substituted for T['value'].

Note that for backwards compatibility reasons, the expression obj.value is still eagerly resolved to type string | number. The expression must be explicitly coerced to T['value'] using a type annotation or a type assertion in order to get the deferred behavior.

This PR also implements better circularity detection and reporting for indexed access types. For example:

typeT1={x: T1['x'];// Error};

Note that circularities may sometimes result only for certain arguments to type parameters.

typeT2<Kextends'x'|'y'>={x: T2<K>[K];// Errory: number;}declareletobj: T2<'x'>;letx=obj.x;

If the type of obj above is changed to T2<'y'> the circularity error goes away.

Fixes#12651.
Fixes#12723.
Fixes#12744.

# Conflicts:
#	src/compiler/checker.ts
#	tests/baselines/reference/keyofAndIndexedAccess.js
#	tests/baselines/reference/keyofAndIndexedAccess.symbols
#	tests/baselines/reference/keyofAndIndexedAccess.types
#	tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts
@eschwartz

Copy link
Copy Markdown

I just want to point out that once this is fixed, we should be able to implement a better EventEmitter definition, with typed events.

For example

// Encapulate an event's name and datainterfaceEventType<TNameextendsstring,TDataextendsany>{name: TName;data: TData;}classEventEmitter<TEventTypeextendsEventType<string,any>>{on<TTypeextendsTEventType>(name: TType["name"],listener:(event: TType["data"])=>void):this;/*...*/}

Usage:

typeEventTypeA=EventType<'a',{foo: string;}>;typeEventTypeB=EventType<'b',{bar: string;}>;constemitter=newEventEmitter<EventTypeA|EventTypeB>();// emitter.on requires that the event name and data match the provided EventTypeemitter.on<EventTypeA>('a',(evt)=>{evt.foo;});emitter.on(EventTypeB>('b',(evt)=>{evt.bar;});

@eschwartz

Copy link
Copy Markdown

Any idea when this might be released? Should we be expecting a 2.1.5 to come out soon with this fix?

(also, thanks for all the work on this. This is really cool stuff, and I'm having a ton of fun using it)

@rotemdan

Rotem Dan (rotemdan) commented Dec 10, 2016

Copy link
Copy Markdown

I believe I've found an alternative, though less elegant, approach to my dispatcher example that doesn't rely on discriminated unions and might work with the new inference capability described here without any need for additional syntax:

typeDispatcherSchema={[name: string]: {argTypes: any[];returnType: any}};classDispatcher<SextendsDispatcherSchema>{dispatch<KextendskeyofS>(name: K,args: S[K]['argTypes']): S[K]['returnType']{// ...}}typeMySchema={"read": {argTypes: [string,number];returnType: string[];};"write": {argTypes: [string,string[],boolean];returnType: number;};}constdispatcher=newDispatcher<MySchema>();varresult=dispatcher.dispatch("read",["myfile.txt",35]);// okvarresult=dispatcher.dispatch("read","myfile.txt");// already errorsvarresult=dispatcher.dispatch("reed",["myfile.txt",35]);// already errorsvarresult=dispatcher.dispatch("write",["myfile.txt","oops",true]);// might error with this PR?

It seems promising but I have not tested this yet though (I'm waiting for the pull request to be merged and arrive to the nightly builds).

(If this does prove to work I'll probably start applying this pattern literally immediately in my code...)

@eschwartz

Copy link
Copy Markdown

Just downloaded typescript@2.2.0-dev.20161212, and my EventEmitter example is working great 👍

@eschwartz

Copy link
Copy Markdown

Any chance this can make it into 2.1.5?

@microsoftMicrosoft (microsoft) locked and limited conversation to collaborators Jun 19, 2018
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

5 participants

@ahejlsberg@eschwartz@rotemdan@mhegazy@msftclas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Defer indexed access T[K] with non-generic K - #12770

Merged
Anders Hejlsberg (ahejlsberg) merged 6 commits into
masterfrom
deferIndexedAccess
Dec 10, 2016
Merged

Defer indexed access T[K] with non-generic K#12770
Anders Hejlsberg (ahejlsberg) merged 6 commits into
masterfrom
deferIndexedAccess

Conversation

@ahejlsberg

@ahejlsbergAnders Hejlsberg (ahejlsberg) commented Dec 8, 2016

Copy link
Copy Markdown
Member

With this PR we defer resolution of indexed access types T[K] where T is generic and K is non-generic.

functiongetValue<Textends{value: string|number}>(obj: T): T['value']{returnobj.value;}letx1=getValue({value: 'hello'});// stringletx2=getValue({value: 42});// number

In the example above, the indexed access type T['value'] is permitted because T is constrained to a type that has a property named value. The type T['value'] behaves like a subtype of string | number because that is the type of value in the constraint type, and when instantiation substitutes an actual type for T, the type of the value property in that actual type is substituted for T['value'].

Note that for backwards compatibility reasons, the expression obj.value is still eagerly resolved to type string | number. The expression must be explicitly coerced to T['value'] using a type annotation or a type assertion in order to get the deferred behavior.

This PR also implements better circularity detection and reporting for indexed access types. For example:

typeT1={x: T1['x'];// Error};

Note that circularities may sometimes result only for certain arguments to type parameters.

typeT2<Kextends'x'|'y'>={x: T2<K>[K];// Errory: number;}declareletobj: T2<'x'>;letx=obj.x;

If the type of obj above is changed to T2<'y'> the circularity error goes away.

Fixes#12651.
Fixes#12723.
Fixes#12744.

# Conflicts:
#	src/compiler/checker.ts
#	tests/baselines/reference/keyofAndIndexedAccess.js
#	tests/baselines/reference/keyofAndIndexedAccess.symbols
#	tests/baselines/reference/keyofAndIndexedAccess.types
#	tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts
@eschwartz

Copy link
Copy Markdown

I just want to point out that once this is fixed, we should be able to implement a better EventEmitter definition, with typed events.

For example

// Encapulate an event's name and datainterfaceEventType<TNameextendsstring,TDataextendsany>{name: TName;data: TData;}classEventEmitter<TEventTypeextendsEventType<string,any>>{on<TTypeextendsTEventType>(name: TType["name"],listener:(event: TType["data"])=>void):this;/*...*/}

Usage:

typeEventTypeA=EventType<'a',{foo: string;}>;typeEventTypeB=EventType<'b',{bar: string;}>;constemitter=newEventEmitter<EventTypeA|EventTypeB>();// emitter.on requires that the event name and data match the provided EventTypeemitter.on<EventTypeA>('a',(evt)=>{evt.foo;});emitter.on(EventTypeB>('b',(evt)=>{evt.bar;});

@eschwartz

Copy link
Copy Markdown

Any idea when this might be released? Should we be expecting a 2.1.5 to come out soon with this fix?

(also, thanks for all the work on this. This is really cool stuff, and I'm having a ton of fun using it)

@rotemdan

Rotem Dan (rotemdan) commented Dec 10, 2016

Copy link
Copy Markdown

I believe I've found an alternative, though less elegant, approach to my dispatcher example that doesn't rely on discriminated unions and might work with the new inference capability described here without any need for additional syntax:

typeDispatcherSchema={[name: string]: {argTypes: any[];returnType: any}};classDispatcher<SextendsDispatcherSchema>{dispatch<KextendskeyofS>(name: K,args: S[K]['argTypes']): S[K]['returnType']{// ...}}typeMySchema={"read": {argTypes: [string,number];returnType: string[];};"write": {argTypes: [string,string[],boolean];returnType: number;};}constdispatcher=newDispatcher<MySchema>();varresult=dispatcher.dispatch("read",["myfile.txt",35]);// okvarresult=dispatcher.dispatch("read","myfile.txt");// already errorsvarresult=dispatcher.dispatch("reed",["myfile.txt",35]);// already errorsvarresult=dispatcher.dispatch("write",["myfile.txt","oops",true]);// might error with this PR?

It seems promising but I have not tested this yet though (I'm waiting for the pull request to be merged and arrive to the nightly builds).

(If this does prove to work I'll probably start applying this pattern literally immediately in my code...)

@eschwartz

Copy link
Copy Markdown

Just downloaded typescript@2.2.0-dev.20161212, and my EventEmitter example is working great 👍

@eschwartz

Copy link
Copy Markdown

Any chance this can make it into 2.1.5?

@microsoftMicrosoft (microsoft) locked and limited conversation to collaborators Jun 19, 2018
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

5 participants

@ahejlsberg@eschwartz@rotemdan@mhegazy@msftclas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Defer indexed access T[K] with non-generic K - #12770

Merged
Anders Hejlsberg (ahejlsberg) merged 6 commits into
masterfrom
deferIndexedAccess
Dec 10, 2016
Merged

Defer indexed access T[K] with non-generic K#12770
Anders Hejlsberg (ahejlsberg) merged 6 commits into
masterfrom
deferIndexedAccess

Conversation

@ahejlsberg

@ahejlsbergAnders Hejlsberg (ahejlsberg) commented Dec 8, 2016

Copy link
Copy Markdown
Member

With this PR we defer resolution of indexed access types T[K] where T is generic and K is non-generic.

functiongetValue<Textends{value: string|number}>(obj: T): T['value']{returnobj.value;}letx1=getValue({value: 'hello'});// stringletx2=getValue({value: 42});// number

In the example above, the indexed access type T['value'] is permitted because T is constrained to a type that has a property named value. The type T['value'] behaves like a subtype of string | number because that is the type of value in the constraint type, and when instantiation substitutes an actual type for T, the type of the value property in that actual type is substituted for T['value'].

Note that for backwards compatibility reasons, the expression obj.value is still eagerly resolved to type string | number. The expression must be explicitly coerced to T['value'] using a type annotation or a type assertion in order to get the deferred behavior.

This PR also implements better circularity detection and reporting for indexed access types. For example:

typeT1={x: T1['x'];// Error};

Note that circularities may sometimes result only for certain arguments to type parameters.

typeT2<Kextends'x'|'y'>={x: T2<K>[K];// Errory: number;}declareletobj: T2<'x'>;letx=obj.x;

If the type of obj above is changed to T2<'y'> the circularity error goes away.

Fixes#12651.
Fixes#12723.
Fixes#12744.

# Conflicts:
#	src/compiler/checker.ts
#	tests/baselines/reference/keyofAndIndexedAccess.js
#	tests/baselines/reference/keyofAndIndexedAccess.symbols
#	tests/baselines/reference/keyofAndIndexedAccess.types
#	tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts
@eschwartz

Copy link
Copy Markdown

I just want to point out that once this is fixed, we should be able to implement a better EventEmitter definition, with typed events.

For example

// Encapulate an event's name and datainterfaceEventType<TNameextendsstring,TDataextendsany>{name: TName;data: TData;}classEventEmitter<TEventTypeextendsEventType<string,any>>{on<TTypeextendsTEventType>(name: TType["name"],listener:(event: TType["data"])=>void):this;/*...*/}

Usage:

typeEventTypeA=EventType<'a',{foo: string;}>;typeEventTypeB=EventType<'b',{bar: string;}>;constemitter=newEventEmitter<EventTypeA|EventTypeB>();// emitter.on requires that the event name and data match the provided EventTypeemitter.on<EventTypeA>('a',(evt)=>{evt.foo;});emitter.on(EventTypeB>('b',(evt)=>{evt.bar;});

@eschwartz

Copy link
Copy Markdown

Any idea when this might be released? Should we be expecting a 2.1.5 to come out soon with this fix?

(also, thanks for all the work on this. This is really cool stuff, and I'm having a ton of fun using it)

@rotemdan

Rotem Dan (rotemdan) commented Dec 10, 2016

Copy link
Copy Markdown

I believe I've found an alternative, though less elegant, approach to my dispatcher example that doesn't rely on discriminated unions and might work with the new inference capability described here without any need for additional syntax:

typeDispatcherSchema={[name: string]: {argTypes: any[];returnType: any}};classDispatcher<SextendsDispatcherSchema>{dispatch<KextendskeyofS>(name: K,args: S[K]['argTypes']): S[K]['returnType']{// ...}}typeMySchema={"read": {argTypes: [string,number];returnType: string[];};"write": {argTypes: [string,string[],boolean];returnType: number;};}constdispatcher=newDispatcher<MySchema>();varresult=dispatcher.dispatch("read",["myfile.txt",35]);// okvarresult=dispatcher.dispatch("read","myfile.txt");// already errorsvarresult=dispatcher.dispatch("reed",["myfile.txt",35]);// already errorsvarresult=dispatcher.dispatch("write",["myfile.txt","oops",true]);// might error with this PR?

It seems promising but I have not tested this yet though (I'm waiting for the pull request to be merged and arrive to the nightly builds).

(If this does prove to work I'll probably start applying this pattern literally immediately in my code...)

@eschwartz

Copy link
Copy Markdown

Just downloaded typescript@2.2.0-dev.20161212, and my EventEmitter example is working great 👍

@eschwartz

Copy link
Copy Markdown

Any chance this can make it into 2.1.5?

@microsoftMicrosoft (microsoft) locked and limited conversation to collaborators Jun 19, 2018
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

5 participants

@ahejlsberg@eschwartz@rotemdan@mhegazy@msftclas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Defer indexed access T[K] with non-generic K - #12770

Merged
Anders Hejlsberg (ahejlsberg) merged 6 commits into
masterfrom
deferIndexedAccess
Dec 10, 2016
Merged

Defer indexed access T[K] with non-generic K#12770
Anders Hejlsberg (ahejlsberg) merged 6 commits into
masterfrom
deferIndexedAccess

Conversation

@ahejlsberg

@ahejlsbergAnders Hejlsberg (ahejlsberg) commented Dec 8, 2016

Copy link
Copy Markdown
Member

With this PR we defer resolution of indexed access types T[K] where T is generic and K is non-generic.

functiongetValue<Textends{value: string|number}>(obj: T): T['value']{returnobj.value;}letx1=getValue({value: 'hello'});// stringletx2=getValue({value: 42});// number

In the example above, the indexed access type T['value'] is permitted because T is constrained to a type that has a property named value. The type T['value'] behaves like a subtype of string | number because that is the type of value in the constraint type, and when instantiation substitutes an actual type for T, the type of the value property in that actual type is substituted for T['value'].

Note that for backwards compatibility reasons, the expression obj.value is still eagerly resolved to type string | number. The expression must be explicitly coerced to T['value'] using a type annotation or a type assertion in order to get the deferred behavior.

This PR also implements better circularity detection and reporting for indexed access types. For example:

typeT1={x: T1['x'];// Error};

Note that circularities may sometimes result only for certain arguments to type parameters.

typeT2<Kextends'x'|'y'>={x: T2<K>[K];// Errory: number;}declareletobj: T2<'x'>;letx=obj.x;

If the type of obj above is changed to T2<'y'> the circularity error goes away.

Fixes#12651.
Fixes#12723.
Fixes#12744.

# Conflicts:
#	src/compiler/checker.ts
#	tests/baselines/reference/keyofAndIndexedAccess.js
#	tests/baselines/reference/keyofAndIndexedAccess.symbols
#	tests/baselines/reference/keyofAndIndexedAccess.types
#	tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts
@eschwartz

Copy link
Copy Markdown

I just want to point out that once this is fixed, we should be able to implement a better EventEmitter definition, with typed events.

For example

// Encapulate an event's name and datainterfaceEventType<TNameextendsstring,TDataextendsany>{name: TName;data: TData;}classEventEmitter<TEventTypeextendsEventType<string,any>>{on<TTypeextendsTEventType>(name: TType["name"],listener:(event: TType["data"])=>void):this;/*...*/}

Usage:

typeEventTypeA=EventType<'a',{foo: string;}>;typeEventTypeB=EventType<'b',{bar: string;}>;constemitter=newEventEmitter<EventTypeA|EventTypeB>();// emitter.on requires that the event name and data match the provided EventTypeemitter.on<EventTypeA>('a',(evt)=>{evt.foo;});emitter.on(EventTypeB>('b',(evt)=>{evt.bar;});

@eschwartz

Copy link
Copy Markdown

Any idea when this might be released? Should we be expecting a 2.1.5 to come out soon with this fix?

(also, thanks for all the work on this. This is really cool stuff, and I'm having a ton of fun using it)

@rotemdan

Rotem Dan (rotemdan) commented Dec 10, 2016

Copy link
Copy Markdown

I believe I've found an alternative, though less elegant, approach to my dispatcher example that doesn't rely on discriminated unions and might work with the new inference capability described here without any need for additional syntax:

typeDispatcherSchema={[name: string]: {argTypes: any[];returnType: any}};classDispatcher<SextendsDispatcherSchema>{dispatch<KextendskeyofS>(name: K,args: S[K]['argTypes']): S[K]['returnType']{// ...}}typeMySchema={"read": {argTypes: [string,number];returnType: string[];};"write": {argTypes: [string,string[],boolean];returnType: number;};}constdispatcher=newDispatcher<MySchema>();varresult=dispatcher.dispatch("read",["myfile.txt",35]);// okvarresult=dispatcher.dispatch("read","myfile.txt");// already errorsvarresult=dispatcher.dispatch("reed",["myfile.txt",35]);// already errorsvarresult=dispatcher.dispatch("write",["myfile.txt","oops",true]);// might error with this PR?

It seems promising but I have not tested this yet though (I'm waiting for the pull request to be merged and arrive to the nightly builds).

(If this does prove to work I'll probably start applying this pattern literally immediately in my code...)

@eschwartz

Copy link
Copy Markdown

Just downloaded typescript@2.2.0-dev.20161212, and my EventEmitter example is working great 👍

@eschwartz

Copy link
Copy Markdown

Any chance this can make it into 2.1.5?

@microsoftMicrosoft (microsoft) locked and limited conversation to collaborators Jun 19, 2018
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

5 participants

@ahejlsberg@eschwartz@rotemdan@mhegazy@msftclas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Defer indexed access T[K] with non-generic K - #12770

Merged
Anders Hejlsberg (ahejlsberg) merged 6 commits into
masterfrom
deferIndexedAccess
Dec 10, 2016
Merged

Defer indexed access T[K] with non-generic K#12770
Anders Hejlsberg (ahejlsberg) merged 6 commits into
masterfrom
deferIndexedAccess

Conversation

@ahejlsberg

@ahejlsbergAnders Hejlsberg (ahejlsberg) commented Dec 8, 2016

Copy link
Copy Markdown
Member

With this PR we defer resolution of indexed access types T[K] where T is generic and K is non-generic.

functiongetValue<Textends{value: string|number}>(obj: T): T['value']{returnobj.value;}letx1=getValue({value: 'hello'});// stringletx2=getValue({value: 42});// number

In the example above, the indexed access type T['value'] is permitted because T is constrained to a type that has a property named value. The type T['value'] behaves like a subtype of string | number because that is the type of value in the constraint type, and when instantiation substitutes an actual type for T, the type of the value property in that actual type is substituted for T['value'].

Note that for backwards compatibility reasons, the expression obj.value is still eagerly resolved to type string | number. The expression must be explicitly coerced to T['value'] using a type annotation or a type assertion in order to get the deferred behavior.

This PR also implements better circularity detection and reporting for indexed access types. For example:

typeT1={x: T1['x'];// Error};

Note that circularities may sometimes result only for certain arguments to type parameters.

typeT2<Kextends'x'|'y'>={x: T2<K>[K];// Errory: number;}declareletobj: T2<'x'>;letx=obj.x;

If the type of obj above is changed to T2<'y'> the circularity error goes away.

Fixes#12651.
Fixes#12723.
Fixes#12744.

# Conflicts:
#	src/compiler/checker.ts
#	tests/baselines/reference/keyofAndIndexedAccess.js
#	tests/baselines/reference/keyofAndIndexedAccess.symbols
#	tests/baselines/reference/keyofAndIndexedAccess.types
#	tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts
@eschwartz

Copy link
Copy Markdown

I just want to point out that once this is fixed, we should be able to implement a better EventEmitter definition, with typed events.

For example

// Encapulate an event's name and datainterfaceEventType<TNameextendsstring,TDataextendsany>{name: TName;data: TData;}classEventEmitter<TEventTypeextendsEventType<string,any>>{on<TTypeextendsTEventType>(name: TType["name"],listener:(event: TType["data"])=>void):this;/*...*/}

Usage:

typeEventTypeA=EventType<'a',{foo: string;}>;typeEventTypeB=EventType<'b',{bar: string;}>;constemitter=newEventEmitter<EventTypeA|EventTypeB>();// emitter.on requires that the event name and data match the provided EventTypeemitter.on<EventTypeA>('a',(evt)=>{evt.foo;});emitter.on(EventTypeB>('b',(evt)=>{evt.bar;});

@eschwartz

Copy link
Copy Markdown

Any idea when this might be released? Should we be expecting a 2.1.5 to come out soon with this fix?

(also, thanks for all the work on this. This is really cool stuff, and I'm having a ton of fun using it)

@rotemdan

Rotem Dan (rotemdan) commented Dec 10, 2016

Copy link
Copy Markdown

I believe I've found an alternative, though less elegant, approach to my dispatcher example that doesn't rely on discriminated unions and might work with the new inference capability described here without any need for additional syntax:

typeDispatcherSchema={[name: string]: {argTypes: any[];returnType: any}};classDispatcher<SextendsDispatcherSchema>{dispatch<KextendskeyofS>(name: K,args: S[K]['argTypes']): S[K]['returnType']{// ...}}typeMySchema={"read": {argTypes: [string,number];returnType: string[];};"write": {argTypes: [string,string[],boolean];returnType: number;};}constdispatcher=newDispatcher<MySchema>();varresult=dispatcher.dispatch("read",["myfile.txt",35]);// okvarresult=dispatcher.dispatch("read","myfile.txt");// already errorsvarresult=dispatcher.dispatch("reed",["myfile.txt",35]);// already errorsvarresult=dispatcher.dispatch("write",["myfile.txt","oops",true]);// might error with this PR?

It seems promising but I have not tested this yet though (I'm waiting for the pull request to be merged and arrive to the nightly builds).

(If this does prove to work I'll probably start applying this pattern literally immediately in my code...)

@eschwartz

Copy link
Copy Markdown

Just downloaded typescript@2.2.0-dev.20161212, and my EventEmitter example is working great 👍

@eschwartz

Copy link
Copy Markdown

Any chance this can make it into 2.1.5?

@microsoftMicrosoft (microsoft) locked and limited conversation to collaborators Jun 19, 2018
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

5 participants

@ahejlsberg@eschwartz@rotemdan@mhegazy@msftclas
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Defer indexed access T[K] with non-generic K - #12770

Merged
Anders Hejlsberg (ahejlsberg) merged 6 commits into
masterfrom
deferIndexedAccess
Dec 10, 2016
Merged

Defer indexed access T[K] with non-generic K#12770
Anders Hejlsberg (ahejlsberg) merged 6 commits into
masterfrom
deferIndexedAccess

Conversation

@ahejlsberg

@ahejlsbergAnders Hejlsberg (ahejlsberg) commented Dec 8, 2016

Copy link
Copy Markdown
Member

With this PR we defer resolution of indexed access types T[K] where T is generic and K is non-generic.

functiongetValue<Textends{value: string|number}>(obj: T): T['value']{returnobj.value;}letx1=getValue({value: 'hello'});// stringletx2=getValue({value: 42});// number

In the example above, the indexed access type T['value'] is permitted because T is constrained to a type that has a property named value. The type T['value'] behaves like a subtype of string | number because that is the type of value in the constraint type, and when instantiation substitutes an actual type for T, the type of the value property in that actual type is substituted for T['value'].

Note that for backwards compatibility reasons, the expression obj.value is still eagerly resolved to type string | number. The expression must be explicitly coerced to T['value'] using a type annotation or a type assertion in order to get the deferred behavior.

This PR also implements better circularity detection and reporting for indexed access types. For example:

typeT1={x: T1['x'];// Error};

Note that circularities may sometimes result only for certain arguments to type parameters.

typeT2<Kextends'x'|'y'>={x: T2<K>[K];// Errory: number;}declareletobj: T2<'x'>;letx=obj.x;

If the type of obj above is changed to T2<'y'> the circularity error goes away.

Fixes#12651.
Fixes#12723.
Fixes#12744.

# Conflicts:
#	src/compiler/checker.ts
#	tests/baselines/reference/keyofAndIndexedAccess.js
#	tests/baselines/reference/keyofAndIndexedAccess.symbols
#	tests/baselines/reference/keyofAndIndexedAccess.types
#	tests/cases/conformance/types/keyof/keyofAndIndexedAccess.ts
@eschwartz

Copy link
Copy Markdown

I just want to point out that once this is fixed, we should be able to implement a better EventEmitter definition, with typed events.

For example

// Encapulate an event's name and datainterfaceEventType<TNameextendsstring,TDataextendsany>{name: TName;data: TData;}classEventEmitter<TEventTypeextendsEventType<string,any>>{on<TTypeextendsTEventType>(name: TType["name"],listener:(event: TType["data"])=>void):this;/*...*/}

Usage:

typeEventTypeA=EventType<'a',{foo: string;}>;typeEventTypeB=EventType<'b',{bar: string;}>;constemitter=newEventEmitter<EventTypeA|EventTypeB>();// emitter.on requires that the event name and data match the provided EventTypeemitter.on<EventTypeA>('a',(evt)=>{evt.foo;});emitter.on(EventTypeB>('b',(evt)=>{evt.bar;});

@eschwartz

Copy link
Copy Markdown

Any idea when this might be released? Should we be expecting a 2.1.5 to come out soon with this fix?

(also, thanks for all the work on this. This is really cool stuff, and I'm having a ton of fun using it)

@rotemdan

Rotem Dan (rotemdan) commented Dec 10, 2016

Copy link
Copy Markdown

I believe I've found an alternative, though less elegant, approach to my dispatcher example that doesn't rely on discriminated unions and might work with the new inference capability described here without any need for additional syntax:

typeDispatcherSchema={[name: string]: {argTypes: any[];returnType: any}};classDispatcher<SextendsDispatcherSchema>{dispatch<KextendskeyofS>(name: K,args: S[K]['argTypes']): S[K]['returnType']{// ...}}typeMySchema={"read": {argTypes: [string,number];returnType: string[];};"write": {argTypes: [string,string[],boolean];returnType: number;};}constdispatcher=newDispatcher<MySchema>();varresult=dispatcher.dispatch("read",["myfile.txt",35]);// okvarresult=dispatcher.dispatch("read","myfile.txt");// already errorsvarresult=dispatcher.dispatch("reed",["myfile.txt",35]);// already errorsvarresult=dispatcher.dispatch("write",["myfile.txt","oops",true]);// might error with this PR?

It seems promising but I have not tested this yet though (I'm waiting for the pull request to be merged and arrive to the nightly builds).

(If this does prove to work I'll probably start applying this pattern literally immediately in my code...)

@eschwartz

Copy link
Copy Markdown

Just downloaded typescript@2.2.0-dev.20161212, and my EventEmitter example is working great 👍

@eschwartz

Copy link
Copy Markdown

Any chance this can make it into 2.1.5?

@microsoftMicrosoft (microsoft) locked and limited conversation to collaborators Jun 19, 2018
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

5 participants

@ahejlsberg@eschwartz@rotemdan@mhegazy@msftclas