Do not expand type references in keyof and index access (#58715)

This commit is contained in:
Titian Cernicova-Dragomir 2024-05-31 20:55:06 +03:00 committed by GitHub
parent fc42002a10
commit 389b579a83
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 375 additions and 45 deletions

View File

@ -8590,6 +8590,28 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return enterNewScope(context, node, getParametersInScope(node), getTypeParametersInScope(node));
}
function tryVisitTypeReference(node: TypeReferenceNode) {
if (canReuseTypeNode(context, node)) {
const { introducesError, node: newName } = trackExistingEntityName(node.typeName, context);
const typeArguments = visitNodes(node.typeArguments, visitExistingNodeTreeSymbols, isTypeNode);
if (!introducesError) {
const updated = factory.updateTypeReferenceNode(
node,
newName,
typeArguments,
);
return setTextRange(context, updated, node);
}
else {
const serializedName = serializeTypeName(context, node.typeName, /*isTypeOf*/ false, typeArguments);
if (serializedName) {
return setTextRange(context, serializedName, node.typeName);
}
}
}
}
function visitExistingNodeTreeSymbolsWorker(node: Node): Node | undefined {
if (isJSDocTypeExpression(node)) {
// Unwrap JSDocTypeExpressions
@ -8682,7 +8704,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (canReuseTypeNode(context, node)) {
return node;
}
return serializeExistingTypeNode(context, node);
hadError = true;
return node;
}
if (isTypeParameterDeclaration(node)) {
return factory.updateTypeParameterDeclaration(
@ -8693,27 +8716,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
visitNode(node.default, visitExistingNodeTreeSymbols, isTypeNode),
);
}
if (isTypeReferenceNode(node)) {
if (canReuseTypeNode(context, node)) {
const { introducesError, node: newName } = trackExistingEntityName(node.typeName, context);
const typeArguments = visitNodes(node.typeArguments, visitExistingNodeTreeSymbols, isTypeNode);
if (!introducesError) {
const updated = factory.updateTypeReferenceNode(
node,
newName,
typeArguments,
);
return setTextRange(context, updated, node);
}
else {
const serializedName = serializeTypeName(context, node.typeName, /*isTypeOf*/ false, typeArguments);
if (serializedName) {
return setTextRange(context, serializedName, node.typeName);
}
}
if (isIndexedAccessTypeNode(node) && isTypeReferenceNode(node.objectType)) {
const objectType = tryVisitTypeReference(node.objectType);
if (!objectType) {
hadError = true;
return node;
}
return serializeExistingTypeNode(context, node);
return factory.updateIndexedAccessTypeNode(node, objectType, visitNode(node.indexType, visitExistingNodeTreeSymbols, isTypeNode)!);
}
if (isTypeReferenceNode(node)) {
const result = tryVisitTypeReference(node);
if (result) {
return result;
}
hadError = true;
return node;
}
if (isLiteralImportTypeNode(node)) {
const nodeSymbol = getNodeLinks(node).resolvedSymbol;
@ -8766,7 +8785,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (serializedName) {
return setTextRange(context, serializedName, node.exprName);
}
return serializeExistingTypeNode(context, node);
hadError = true;
return node;
}
return factory.updateTypeQueryNode(
node,
@ -8838,9 +8858,22 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
);
}
if (isTypeOperatorNode(node) && node.operator === SyntaxKind.UniqueKeyword && node.type.kind === SyntaxKind.SymbolKeyword) {
if (!canReuseTypeNode(context, node)) {
return serializeExistingTypeNode(context, node);
if (isTypeOperatorNode(node)) {
if (node.operator === SyntaxKind.UniqueKeyword && node.type.kind === SyntaxKind.SymbolKeyword) {
if (!canReuseTypeNode(context, node)) {
hadError = true;
return node;
}
}
else if (node.operator === SyntaxKind.KeyOfKeyword) {
if (isTypeReferenceNode(node.type)) {
const type = tryVisitTypeReference(node.type);
if (!type) {
hadError = true;
return node;
}
return factory.updateTypeOperatorNode(node, type);
}
}
}

View File

@ -822,7 +822,7 @@ function ff1() {
}
function apply<K extends Keys>(funKey: K, ...args: ArgMap[K]) {
>apply : <K extends keyof { sum: [a: number, b: number]; concat: [a: string, b: string, c: string]; }>(funKey: K, ...args: { sum: [a: number, b: number]; concat: [a: string, b: string, c: string]; }[K]) => void
> : ^ ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^ ^^ ^^^^^ ^^^^^^^^^ ^^^^^^^^^^ ^^^ ^^^^^^^^^
> : ^ ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^ ^^ ^^^^^ ^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^
>funKey : K
> : ^
>args : { sum: [a: number, b: number]; concat: [a: string, b: string, c: string]; }[K]
@ -854,7 +854,7 @@ function ff1() {
>apply('sum', 1, 2) : void
> : ^^^^
>apply : <K extends keyof { sum: [a: number, b: number]; concat: [a: string, b: string, c: string]; }>(funKey: K, ...args: { sum: [a: number, b: number]; concat: [a: string, b: string, c: string]; }[K]) => void
> : ^ ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^ ^^ ^^^^^ ^^^^^^^^^ ^^^^^^^^^^ ^^^ ^^^^^^^^^
> : ^ ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^ ^^ ^^^^^ ^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^
>'sum' : "sum"
> : ^^^^^
>1 : 1
@ -868,7 +868,7 @@ function ff1() {
>apply('concat', 'str1', 'str2', 'str3' ) : void
> : ^^^^
>apply : <K extends keyof { sum: [a: number, b: number]; concat: [a: string, b: string, c: string]; }>(funKey: K, ...args: { sum: [a: number, b: number]; concat: [a: string, b: string, c: string]; }[K]) => void
> : ^ ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^ ^^ ^^^^^ ^^^^^^^^^ ^^^^^^^^^^ ^^^ ^^^^^^^^^
> : ^ ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^ ^^ ^^^^^ ^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^
>'concat' : "concat"
> : ^^^^^^^^
>'str1' : "str1"

View File

@ -0,0 +1,85 @@
//// [tests/cases/compiler/declarationEmitAliasInlineing.ts] ////
//// [a.ts]
type O = {
prop: string
prop2: string
}
type I = {
prop: string
}
export const fn = (v: O['prop'], p: Omit<O, 'prop'>, key: keyof O, p2: Omit<O, keyof I>) => {};
//// [aExp.ts]
export type O = {
prop: string
prop2: string
}
export type I = {
prop: string
}
export const fnExp = (v: O['prop'], p: Omit<O, 'prop'>, key: keyof O, p2: Omit<O, keyof I>) => {};
//// [b.ts]
import {fn} from './a'
import {fnExp} from './aExp'
export const f = fn;
export const fExp = fnExp;
//// [a.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.fn = void 0;
var fn = function (v, p, key, p2) { };
exports.fn = fn;
//// [aExp.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.fnExp = void 0;
var fnExp = function (v, p, key, p2) { };
exports.fnExp = fnExp;
//// [b.js]
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.fExp = exports.f = void 0;
var a_1 = require("./a");
var aExp_1 = require("./aExp");
exports.f = a_1.fn;
exports.fExp = aExp_1.fnExp;
//// [a.d.ts]
type O = {
prop: string;
prop2: string;
};
type I = {
prop: string;
};
export declare const fn: (v: O["prop"], p: Omit<O, "prop">, key: keyof O, p2: Omit<O, keyof I>) => void;
export {};
//// [aExp.d.ts]
export type O = {
prop: string;
prop2: string;
};
export type I = {
prop: string;
};
export declare const fnExp: (v: O["prop"], p: Omit<O, "prop">, key: keyof O, p2: Omit<O, keyof I>) => void;
//// [b.d.ts]
export declare const f: (v: string, p: Omit<{
prop: string;
prop2: string;
}, "prop">, key: keyof {
prop: string;
prop2: string;
}, p2: Omit<{
prop: string;
prop2: string;
}, "prop">) => void;
export declare const fExp: (v: import("./aExp").O["prop"], p: Omit<import("./aExp").O, "prop">, key: keyof import("./aExp").O, p2: Omit<import("./aExp").O, keyof import("./aExp").I>) => void;

View File

@ -0,0 +1,81 @@
//// [tests/cases/compiler/declarationEmitAliasInlineing.ts] ////
=== a.ts ===
type O = {
>O : Symbol(O, Decl(a.ts, 0, 0))
prop: string
>prop : Symbol(prop, Decl(a.ts, 0, 10))
prop2: string
>prop2 : Symbol(prop2, Decl(a.ts, 1, 16))
}
type I = {
>I : Symbol(I, Decl(a.ts, 3, 1))
prop: string
>prop : Symbol(prop, Decl(a.ts, 5, 10))
}
export const fn = (v: O['prop'], p: Omit<O, 'prop'>, key: keyof O, p2: Omit<O, keyof I>) => {};
>fn : Symbol(fn, Decl(a.ts, 9, 12))
>v : Symbol(v, Decl(a.ts, 9, 19))
>O : Symbol(O, Decl(a.ts, 0, 0))
>p : Symbol(p, Decl(a.ts, 9, 32))
>Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --))
>O : Symbol(O, Decl(a.ts, 0, 0))
>key : Symbol(key, Decl(a.ts, 9, 52))
>O : Symbol(O, Decl(a.ts, 0, 0))
>p2 : Symbol(p2, Decl(a.ts, 9, 66))
>Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --))
>O : Symbol(O, Decl(a.ts, 0, 0))
>I : Symbol(I, Decl(a.ts, 3, 1))
=== aExp.ts ===
export type O = {
>O : Symbol(O, Decl(aExp.ts, 0, 0))
prop: string
>prop : Symbol(prop, Decl(aExp.ts, 0, 17))
prop2: string
>prop2 : Symbol(prop2, Decl(aExp.ts, 1, 16))
}
export type I = {
>I : Symbol(I, Decl(aExp.ts, 3, 1))
prop: string
>prop : Symbol(prop, Decl(aExp.ts, 5, 17))
}
export const fnExp = (v: O['prop'], p: Omit<O, 'prop'>, key: keyof O, p2: Omit<O, keyof I>) => {};
>fnExp : Symbol(fnExp, Decl(aExp.ts, 9, 12))
>v : Symbol(v, Decl(aExp.ts, 9, 22))
>O : Symbol(O, Decl(aExp.ts, 0, 0))
>p : Symbol(p, Decl(aExp.ts, 9, 35))
>Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --))
>O : Symbol(O, Decl(aExp.ts, 0, 0))
>key : Symbol(key, Decl(aExp.ts, 9, 55))
>O : Symbol(O, Decl(aExp.ts, 0, 0))
>p2 : Symbol(p2, Decl(aExp.ts, 9, 69))
>Omit : Symbol(Omit, Decl(lib.es5.d.ts, --, --))
>O : Symbol(O, Decl(aExp.ts, 0, 0))
>I : Symbol(I, Decl(aExp.ts, 3, 1))
=== b.ts ===
import {fn} from './a'
>fn : Symbol(fn, Decl(b.ts, 0, 8))
import {fnExp} from './aExp'
>fnExp : Symbol(fnExp, Decl(b.ts, 1, 8))
export const f = fn;
>f : Symbol(f, Decl(b.ts, 2, 12))
>fn : Symbol(fn, Decl(b.ts, 0, 8))
export const fExp = fnExp;
>fExp : Symbol(fExp, Decl(b.ts, 3, 12))
>fnExp : Symbol(fnExp, Decl(b.ts, 1, 8))

View File

@ -0,0 +1,97 @@
//// [tests/cases/compiler/declarationEmitAliasInlineing.ts] ////
=== a.ts ===
type O = {
>O : O
> : ^
prop: string
>prop : string
> : ^^^^^^
prop2: string
>prop2 : string
> : ^^^^^^
}
type I = {
>I : I
> : ^
prop: string
>prop : string
> : ^^^^^^
}
export const fn = (v: O['prop'], p: Omit<O, 'prop'>, key: keyof O, p2: Omit<O, keyof I>) => {};
>fn : (v: O["prop"], p: Omit<O, "prop">, key: keyof O, p2: Omit<O, keyof I>) => void
> : ^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^^^^^
>(v: O['prop'], p: Omit<O, 'prop'>, key: keyof O, p2: Omit<O, keyof I>) => {} : (v: O["prop"], p: Omit<O, "prop">, key: keyof O, p2: Omit<O, keyof I>) => void
> : ^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^^^^^
>v : string
> : ^^^^^^
>p : Omit<O, "prop">
> : ^^^^^^^^^^^^^^^
>key : keyof O
> : ^^^^^^^
>p2 : Omit<O, "prop">
> : ^^^^^^^^^^^^^^^
=== aExp.ts ===
export type O = {
>O : O
> : ^
prop: string
>prop : string
> : ^^^^^^
prop2: string
>prop2 : string
> : ^^^^^^
}
export type I = {
>I : I
> : ^
prop: string
>prop : string
> : ^^^^^^
}
export const fnExp = (v: O['prop'], p: Omit<O, 'prop'>, key: keyof O, p2: Omit<O, keyof I>) => {};
>fnExp : (v: O["prop"], p: Omit<O, "prop">, key: keyof O, p2: Omit<O, keyof I>) => void
> : ^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^^^^^
>(v: O['prop'], p: Omit<O, 'prop'>, key: keyof O, p2: Omit<O, keyof I>) => {} : (v: O["prop"], p: Omit<O, "prop">, key: keyof O, p2: Omit<O, keyof I>) => void
> : ^ ^^ ^^ ^^ ^^ ^^ ^^ ^^ ^^^^^^^^^
>v : string
> : ^^^^^^
>p : Omit<O, "prop">
> : ^^^^^^^^^^^^^^^
>key : keyof O
> : ^^^^^^^
>p2 : Omit<O, "prop">
> : ^^^^^^^^^^^^^^^
=== b.ts ===
import {fn} from './a'
>fn : (v: string, p: Omit<{ prop: string; prop2: string; }, "prop">, key: keyof { prop: string; prop2: string; }, p2: Omit<{ prop: string; prop2: string; }, "prop">) => void
> : ^ ^^^^^^^^^^ ^^ ^^^^^^^^ ^^^^^^^^^ ^^^ ^^ ^^^^^^^^^^^^^^^^ ^^^^^^^^^ ^^^^^ ^^ ^^^^^^^^ ^^^^^^^^^ ^^^ ^^^^^^ ^^^^^^^^^
import {fnExp} from './aExp'
>fnExp : (v: import("aExp").O["prop"], p: Omit<import("aExp").O, "prop">, key: keyof import("aExp").O, p2: Omit<import("aExp").O, keyof import("aExp").I>) => void
> : ^ ^^ ^^^^^^ ^ ^^ ^^ ^^^^^^ ^ ^^ ^^ ^^^^^^ ^^^ ^^ ^^^^^^ ^ ^^^^^^ ^ ^^^^^^^^^
export const f = fn;
>f : (v: string, p: Omit<{ prop: string; prop2: string; }, "prop">, key: keyof { prop: string; prop2: string; }, p2: Omit<{ prop: string; prop2: string; }, "prop">) => void
> : ^ ^^^^^^^^^^ ^^ ^^^^^^^^ ^^^^^^^^^ ^^^ ^^ ^^^^^^^^^^^^^^^^ ^^^^^^^^^ ^^^^^ ^^ ^^^^^^^^ ^^^^^^^^^ ^^^ ^^^^^^ ^^^^^^^^^
>fn : (v: string, p: Omit<{ prop: string; prop2: string; }, "prop">, key: keyof { prop: string; prop2: string; }, p2: Omit<{ prop: string; prop2: string; }, "prop">) => void
> : ^ ^^^^^^^^^^ ^^ ^^^^^^^^ ^^^^^^^^^ ^^^ ^^ ^^^^^^^^^^^^^^^^ ^^^^^^^^^ ^^^^^ ^^ ^^^^^^^^ ^^^^^^^^^ ^^^ ^^^^^^ ^^^^^^^^^
export const fExp = fnExp;
>fExp : (v: import("aExp").O["prop"], p: Omit<import("aExp").O, "prop">, key: keyof import("aExp").O, p2: Omit<import("aExp").O, keyof import("aExp").I>) => void
> : ^ ^^ ^^^^^^ ^ ^^ ^^ ^^^^^^ ^ ^^ ^^ ^^^^^^ ^^^ ^^ ^^^^^^ ^ ^^^^^^ ^ ^^^^^^^^^
>fnExp : (v: import("aExp").O["prop"], p: Omit<import("aExp").O, "prop">, key: keyof import("aExp").O, p2: Omit<import("aExp").O, keyof import("aExp").I>) => void
> : ^ ^^ ^^^^^^ ^ ^^ ^^ ^^^^^^ ^ ^^ ^^ ^^^^^^ ^^^ ^^ ^^^^^^ ^ ^^^^^^ ^ ^^^^^^^^^

View File

@ -57,7 +57,7 @@ export class Foo<C> extends Parent<IData<C>> {
>this.getData().get('content') : C
> : ^
>this.getData().get : <K extends "content">(prop: K) => IData<C>[K]
> : ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ ^
> : ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
>this.getData() : Data<IData<C>>
> : ^^^^^^^^^^^^^^
>this.getData : () => Data<IData<C>>
@ -67,7 +67,7 @@ export class Foo<C> extends Parent<IData<C>> {
>getData : () => Data<IData<C>>
> : ^^^^^^ ^^^^^^^^
>get : <K extends "content">(prop: K) => IData<C>[K]
> : ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^ ^
> : ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^
>'content' : "content"
> : ^^^^^^^^^
}
@ -87,7 +87,7 @@ export class Bar<C, T extends IData<C>> extends Parent<T> {
>this.getData().get('content') : T["content"]
> : ^^^^^^^^^^^^
>this.getData().get : <K extends keyof T>(prop: K) => T[K]
> : ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^ ^
> : ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^
>this.getData() : Data<T>
> : ^^^^^^^
>this.getData : () => Data<T>
@ -97,7 +97,7 @@ export class Bar<C, T extends IData<C>> extends Parent<T> {
>getData : () => Data<T>
> : ^^^^^^ ^
>get : <K extends keyof T>(prop: K) => T[K]
> : ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^ ^
> : ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^
>'content' : "content"
> : ^^^^^^^^^
}

View File

@ -690,7 +690,7 @@ const result = invoker('test', true)({ test: (a: boolean) => 123 })
>invoker('test', true)({ test: (a: boolean) => 123 }) : number
> : ^^^^^^
>invoker('test', true) : <T extends Record<"test", (args_0: boolean) => any>>(obj: T) => ReturnType<T["test"]>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^ ^ ^^^^^^
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^ ^^^^^^^^ ^^^^^^^^^
>invoker : <K extends string | number | symbol, A extends any[]>(key: K, ...args: A) => <T extends Record<K, (...args: A) => any>>(obj: T) => ReturnType<T[K]>
> : ^ ^^^^^^^^^ ^^ ^^^^^^^^^ ^^ ^^ ^^^^^ ^^ ^^^^^^ ^^^^^^^^^ ^^ ^^ ^^^^^
>'test' : "test"

View File

@ -46,8 +46,8 @@ const v = chain({a: 1, b: 2}).mapValues(square).value();
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>chain({a: 1, b: 2}).mapValues(square) : Chainable<{ a: number; b: number; }>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>chain({a: 1, b: 2}).mapValues : <U>(func: (v: number) => U) => Chainable<{ [k in keyof { a: number; b: number; }]: U; }>
> : ^^^^ ^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ ^
>chain({a: 1, b: 2}).mapValues : <U>(func: (v: number) => U) => Chainable<{ [k in "a" | "b"]: U; }>
> : ^^^^ ^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^ ^
>chain({a: 1, b: 2}) : Chainable<{ a: number; b: number; }>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>chain : <T>(t: T) => Chainable<T>
@ -62,8 +62,8 @@ const v = chain({a: 1, b: 2}).mapValues(square).value();
> : ^^^^^^
>2 : 2
> : ^
>mapValues : <U>(func: (v: number) => U) => Chainable<{ [k in keyof { a: number; b: number; }]: U; }>
> : ^^^^ ^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^ ^
>mapValues : <U>(func: (v: number) => U) => Chainable<{ [k in "a" | "b"]: U; }>
> : ^^^^ ^^^ ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^ ^
>square : (x: number) => number
> : ^ ^^ ^^^^^^^^^^^
>value : () => { a: number; b: number; }

View File

@ -679,11 +679,11 @@ p.getIndex(0); // ok, 0 is a valid index
>p.getIndex(0) : number
> : ^^^^^^
>p.getIndex : <I extends 0 | 1>(index: I) => FieldType<Extract<[{ name: "x"; type: "f64"; }, { name: "y"; type: "f64"; }][I], FieldDefinition>["type"]>
> : ^^^^^^^^^^^^^^^^^^ ^^^^^^^^ ^^^^^^^^^ ^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^ ^^^^ ^
> : ^^^^^^^^^^^^^^^^^^ ^^^^^^^^ ^^^^^^^^^ ^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^ ^^^^^^^
>p : Point
> : ^^^^^
>getIndex : <I extends 0 | 1>(index: I) => FieldType<Extract<[{ name: "x"; type: "f64"; }, { name: "y"; type: "f64"; }][I], FieldDefinition>["type"]>
> : ^^^^^^^^^^^^^^^^^^ ^^^^^^^^ ^^^^^^^^^ ^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^ ^^^^ ^
> : ^^^^^^^^^^^^^^^^^^ ^^^^^^^^ ^^^^^^^^^ ^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^ ^^^^^^^
>0 : 0
> : ^
@ -691,11 +691,11 @@ p.getIndex(1); // ok, 1 is a valid index
>p.getIndex(1) : number
> : ^^^^^^
>p.getIndex : <I extends 0 | 1>(index: I) => FieldType<Extract<[{ name: "x"; type: "f64"; }, { name: "y"; type: "f64"; }][I], FieldDefinition>["type"]>
> : ^^^^^^^^^^^^^^^^^^ ^^^^^^^^ ^^^^^^^^^ ^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^ ^^^^ ^
> : ^^^^^^^^^^^^^^^^^^ ^^^^^^^^ ^^^^^^^^^ ^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^ ^^^^^^^
>p : Point
> : ^^^^^
>getIndex : <I extends 0 | 1>(index: I) => FieldType<Extract<[{ name: "x"; type: "f64"; }, { name: "y"; type: "f64"; }][I], FieldDefinition>["type"]>
> : ^^^^^^^^^^^^^^^^^^ ^^^^^^^^ ^^^^^^^^^ ^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^ ^^^^ ^
> : ^^^^^^^^^^^^^^^^^^ ^^^^^^^^ ^^^^^^^^^ ^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^ ^^^^^^^
>1 : 1
> : ^
@ -703,11 +703,11 @@ p.getIndex(2); // error, 2 is not a valid index
>p.getIndex(2) : number
> : ^^^^^^
>p.getIndex : <I extends 0 | 1>(index: I) => FieldType<Extract<[{ name: "x"; type: "f64"; }, { name: "y"; type: "f64"; }][I], FieldDefinition>["type"]>
> : ^^^^^^^^^^^^^^^^^^ ^^^^^^^^ ^^^^^^^^^ ^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^ ^^^^ ^
> : ^^^^^^^^^^^^^^^^^^ ^^^^^^^^ ^^^^^^^^^ ^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^ ^^^^^^^
>p : Point
> : ^^^^^
>getIndex : <I extends 0 | 1>(index: I) => FieldType<Extract<[{ name: "x"; type: "f64"; }, { name: "y"; type: "f64"; }][I], FieldDefinition>["type"]>
> : ^^^^^^^^^^^^^^^^^^ ^^^^^^^^ ^^^^^^^^^ ^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^ ^^^^ ^
> : ^^^^^^^^^^^^^^^^^^ ^^^^^^^^ ^^^^^^^^^ ^^^^^^^^ ^^^^^^^^^^^^^ ^^^^^^^^ ^^^^^^^
>2 : 2
> : ^

View File

@ -33,11 +33,11 @@ switch (tmp.get('t')) {
>tmp.get('t') : "A" | "B"
> : ^^^^^^^^^
>tmp.get : (<K extends "t">(k: K) => A[K]) | (<K extends "t">(k: K) => B[K])
> : ^^^^^^^^^^^^^^^^^ ^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^ ^ ^
> : ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^
>tmp : Test<A> | Test<B>
> : ^^^^^^^^^^^^^^^^^
>get : (<K extends "t">(k: K) => A[K]) | (<K extends "t">(k: K) => B[K])
> : ^^^^^^^^^^^^^^^^^ ^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^ ^ ^
> : ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^
>'t' : "t"
> : ^^^

View File

@ -0,0 +1,34 @@
// @declaration: true
// @strict: true
// @filename: a.ts
type O = {
prop: string
prop2: string
}
type I = {
prop: string
}
export const fn = (v: O['prop'], p: Omit<O, 'prop'>, key: keyof O, p2: Omit<O, keyof I>) => {};
// @filename: aExp.ts
export type O = {
prop: string
prop2: string
}
export type I = {
prop: string
}
export const fnExp = (v: O['prop'], p: Omit<O, 'prop'>, key: keyof O, p2: Omit<O, keyof I>) => {};
// @filename: b.ts
import {fn} from './a'
import {fnExp} from './aExp'
export const f = fn;
export const fExp = fnExp;

View File

@ -34,7 +34,7 @@ verify.quickInfos({
func?: Function;
}, obj: T, key: "name"): "name"`,
4: `function foof<Error, "name">(settings: (row: Error) => {
value: Error["name"];
value: string;
func?: Function;
}, obj: Error, key: "name"): "name"`
});