Compare commits
8 commits
main
...
vue-hacks-
Author | SHA1 | Date | |
---|---|---|---|
|
17173a6e6c | ||
|
32e75f71a3 | ||
|
f3a12d104f | ||
|
6fd5e1bab8 | ||
|
56d18353c6 | ||
|
613aead278 | ||
|
9558c210f4 | ||
|
99743dfdd5 |
|
@ -3504,7 +3504,12 @@ namespace ts {
|
|||
return isPrivateWithinAmbient(memberDeclaration);
|
||||
}
|
||||
|
||||
function getTypeOfVariableOrParameterOrProperty(symbol: Symbol): Type {
|
||||
function getTypeOfVariableOrParameterOrProperty(symbol: Symbol, crazy?: boolean): Type {
|
||||
const declaration = symbol.valueDeclaration;
|
||||
if (crazy && declaration.kind === SyntaxKind.Parameter && (declaration as ParameterDeclaration).contextualType) {
|
||||
// TODO: Doesn't widen of course
|
||||
return getTypeFromTypeNode((declaration as ParameterDeclaration).contextualType);
|
||||
}
|
||||
const links = getSymbolLinks(symbol);
|
||||
if (!links.type) {
|
||||
// Handle prototype property
|
||||
|
@ -3512,7 +3517,6 @@ namespace ts {
|
|||
return links.type = getTypeOfPrototypeProperty(symbol);
|
||||
}
|
||||
// Handle catch clause variables
|
||||
const declaration = symbol.valueDeclaration;
|
||||
if (isCatchClauseVariableDeclarationOrBindingElement(declaration)) {
|
||||
return links.type = anyType;
|
||||
}
|
||||
|
@ -3695,13 +3699,16 @@ namespace ts {
|
|||
return links.type;
|
||||
}
|
||||
|
||||
function getTypeOfInstantiatedSymbol(symbol: Symbol): Type {
|
||||
function getTypeOfInstantiatedSymbol(symbol: Symbol, crazy?: boolean): Type {
|
||||
const links = getSymbolLinks(symbol);
|
||||
if (crazy) {
|
||||
return instantiateType(getTypeOfSymbol(links.target, crazy), links.mapper);
|
||||
}
|
||||
if (!links.type) {
|
||||
if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
|
||||
return unknownType;
|
||||
}
|
||||
let type = instantiateType(getTypeOfSymbol(links.target), links.mapper);
|
||||
let type = instantiateType(getTypeOfSymbol(links.target, crazy), links.mapper);
|
||||
if (!popTypeResolution()) {
|
||||
type = reportCircularityError(symbol);
|
||||
}
|
||||
|
@ -3725,12 +3732,12 @@ namespace ts {
|
|||
return anyType;
|
||||
}
|
||||
|
||||
function getTypeOfSymbol(symbol: Symbol): Type {
|
||||
function getTypeOfSymbol(symbol: Symbol, crazy?: boolean): Type {
|
||||
if (symbol.flags & SymbolFlags.Instantiated) {
|
||||
return getTypeOfInstantiatedSymbol(symbol);
|
||||
return getTypeOfInstantiatedSymbol(symbol, crazy);
|
||||
}
|
||||
if (symbol.flags & (SymbolFlags.Variable | SymbolFlags.Property)) {
|
||||
return getTypeOfVariableOrParameterOrProperty(symbol);
|
||||
return getTypeOfVariableOrParameterOrProperty(symbol, crazy);
|
||||
}
|
||||
if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) {
|
||||
return getTypeOfFuncClassEnumModule(symbol);
|
||||
|
@ -4937,6 +4944,10 @@ namespace ts {
|
|||
return type.resolvedApparentType || (type.resolvedApparentType = getTypeWithThisArgument(type, type));
|
||||
}
|
||||
|
||||
function getApparentTypeOfReturnType(type: ReturnType) {
|
||||
return type.resolvedApparentType || (type.resolvedApparentType = getReturnType(getApparentType(type.type)));
|
||||
}
|
||||
|
||||
/**
|
||||
* For a type parameter, return the base constraint of the type parameter. For the string, number,
|
||||
* boolean, and symbol primitive types, return the corresponding object types. Otherwise return the
|
||||
|
@ -4945,6 +4956,7 @@ namespace ts {
|
|||
function getApparentType(type: Type): Type {
|
||||
const t = type.flags & TypeFlags.TypeVariable ? getBaseConstraintOfType(<TypeVariable>type) || emptyObjectType : type;
|
||||
return t.flags & TypeFlags.Intersection ? getApparentTypeOfIntersectionType(<IntersectionType>t) :
|
||||
t.flags & TypeFlags.Return ? getApparentTypeOfReturnType(<ReturnType>t) :
|
||||
t.flags & TypeFlags.StringLike ? globalStringType :
|
||||
t.flags & TypeFlags.NumberLike ? globalNumberType :
|
||||
t.flags & TypeFlags.BooleanLike ? globalBooleanType :
|
||||
|
@ -6188,6 +6200,29 @@ namespace ts {
|
|||
return links.resolvedType;
|
||||
}
|
||||
|
||||
function getTypeFromReturnOperatorNode(node: ReturnOperatorNode) {
|
||||
const links = getNodeLinks(node);
|
||||
if (!links.resolvedType) {
|
||||
links.resolvedType = getReturnType(getTypeFromTypeNode(node.type));
|
||||
}
|
||||
return links.resolvedType;
|
||||
}
|
||||
|
||||
function getReturnType(type: Type): Type {
|
||||
if (maybeTypeOfKind(type, TypeFlags.TypeVariable)) {
|
||||
return getReturnTypeForGenericType(type as TypeVariable | UnionOrIntersectionType);
|
||||
}
|
||||
return getUnionType(map(getSignaturesOfType(type, SignatureKind.Call), getReturnTypeOfSignature));
|
||||
}
|
||||
|
||||
function getReturnTypeForGenericType(type: TypeVariable | UnionOrIntersectionType): Type {
|
||||
if (!type.resolvedReturnType) {
|
||||
type.resolvedReturnType = <ReturnType>createType(TypeFlags.Return);
|
||||
type.resolvedReturnType.type = type;
|
||||
}
|
||||
return type.resolvedReturnType;
|
||||
}
|
||||
|
||||
function createIndexedAccessType(objectType: Type, indexType: Type) {
|
||||
const type = <IndexedAccessType>createType(TypeFlags.IndexedAccess);
|
||||
type.objectType = objectType;
|
||||
|
@ -6595,7 +6630,9 @@ namespace ts {
|
|||
case SyntaxKind.JSDocFunctionType:
|
||||
return getTypeFromTypeLiteralOrFunctionOrConstructorTypeNode(node);
|
||||
case SyntaxKind.TypeOperator:
|
||||
return getTypeFromTypeOperatorNode(<TypeOperatorNode>node);
|
||||
return getTypeFromTypeOperatorNode(node as TypeOperatorNode);
|
||||
case SyntaxKind.ReturnOperator:
|
||||
return getTypeFromReturnOperatorNode(node as ReturnOperatorNode);
|
||||
case SyntaxKind.IndexedAccessType:
|
||||
return getTypeFromIndexedAccessTypeNode(<IndexedAccessTypeNode>node);
|
||||
case SyntaxKind.MappedType:
|
||||
|
@ -6962,6 +6999,9 @@ namespace ts {
|
|||
if (type.flags & TypeFlags.Index) {
|
||||
return getIndexType(instantiateType((<IndexType>type).type, mapper));
|
||||
}
|
||||
if (type.flags & TypeFlags.Return) {
|
||||
return getReturnType(instantiateType((<ReturnType>type).type, mapper));
|
||||
}
|
||||
if (type.flags & TypeFlags.IndexedAccess) {
|
||||
return getIndexedAccessType(instantiateType((<IndexedAccessType>type).objectType, mapper), instantiateType((<IndexedAccessType>type).indexType, mapper));
|
||||
}
|
||||
|
@ -9040,7 +9080,7 @@ namespace ts {
|
|||
// We're inferring from some source type S to a mapped type { [P in T]: X }, where T is a type
|
||||
// parameter. Infer from 'keyof S' to T and infer from a union of each property type in S to X.
|
||||
inferFromTypes(getIndexType(source), constraintType);
|
||||
inferFromTypes(getUnionType(map(getPropertiesOfType(source), getTypeOfSymbol)), getTemplateTypeFromMappedType(<MappedType>target));
|
||||
inferFromTypes(getUnionType(map(getPropertiesOfType(source), p => getTypeOfSymbol(p))), getTemplateTypeFromMappedType(<MappedType>target));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -11229,7 +11269,7 @@ namespace ts {
|
|||
const argIndex = indexOf(args, arg);
|
||||
if (argIndex >= 0) {
|
||||
const signature = getResolvedOrAnySignature(callTarget);
|
||||
return getTypeAtPosition(signature, argIndex);
|
||||
return getSpecialContextualTypeAtPosition(signature, argIndex);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
@ -13064,7 +13104,7 @@ namespace ts {
|
|||
// If the effective argument is 'undefined', then it is an argument that is present but is synthetic.
|
||||
if (arg === undefined || arg.kind !== SyntaxKind.OmittedExpression) {
|
||||
// Check spread elements against rest type (from arity check we know spread argument corresponds to a rest parameter)
|
||||
const paramType = getTypeAtPosition(signature, i);
|
||||
const paramType = getSpecialContextualTypeAtPosition(signature, i);
|
||||
let argType = getEffectiveArgumentType(node, i);
|
||||
|
||||
// If the effective argument type is 'undefined', there is no synthetic type
|
||||
|
@ -14088,8 +14128,8 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
function getTypeOfParameter(symbol: Symbol) {
|
||||
const type = getTypeOfSymbol(symbol);
|
||||
function getTypeOfParameter(symbol: Symbol, crazy?: boolean) {
|
||||
const type = getTypeOfSymbol(symbol, crazy);
|
||||
if (strictNullChecks) {
|
||||
const declaration = symbol.valueDeclaration;
|
||||
if (declaration && (<VariableLikeDeclaration>declaration).initializer) {
|
||||
|
@ -14099,6 +14139,12 @@ namespace ts {
|
|||
return type;
|
||||
}
|
||||
|
||||
function getSpecialContextualTypeAtPosition(signature: Signature, pos: number): Type {
|
||||
return signature.hasRestParameter ?
|
||||
pos < signature.parameters.length - 1 ? getTypeOfParameter(signature.parameters[pos], /*crazy*/ true) : getRestTypeOfSignature(signature) :
|
||||
pos < signature.parameters.length ? getTypeOfParameter(signature.parameters[pos], /*crazy*/ true) : anyType;
|
||||
}
|
||||
|
||||
function getTypeAtPosition(signature: Signature, pos: number): Type {
|
||||
return signature.hasRestParameter ?
|
||||
pos < signature.parameters.length - 1 ? getTypeOfParameter(signature.parameters[pos]) : getRestTypeOfSignature(signature) :
|
||||
|
@ -15751,7 +15797,18 @@ namespace ts {
|
|||
|
||||
checkTypeParameters(node.typeParameters);
|
||||
|
||||
forEach(node.parameters, checkParameter);
|
||||
const isObjectLiteralMethodWithThis = isObjectLiteralMethod(node) &&
|
||||
node.parameters &&
|
||||
node.parameters.length &&
|
||||
parameterIsThisKeyword(node.parameters[0]);
|
||||
if (isObjectLiteralMethodWithThis) {
|
||||
// defer checking on first one
|
||||
checkNodeDeferred(node.parameters[0]); // .. this will surely work ..
|
||||
forEach(node.parameters.slice(1), checkParameter);
|
||||
}
|
||||
else {
|
||||
forEach(node.parameters, checkParameter);
|
||||
}
|
||||
|
||||
if (node.type) {
|
||||
checkSourceElement(node.type);
|
||||
|
|
|
@ -89,6 +89,7 @@ namespace ts {
|
|||
visitNode(cbNode, (<VariableLikeDeclaration>node).name) ||
|
||||
visitNode(cbNode, (<VariableLikeDeclaration>node).questionToken) ||
|
||||
visitNode(cbNode, (<VariableLikeDeclaration>node).type) ||
|
||||
visitNode(cbNode, (<ParameterDeclaration>node).contextualType) ||
|
||||
visitNode(cbNode, (<VariableLikeDeclaration>node).initializer);
|
||||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.ConstructorType:
|
||||
|
@ -138,6 +139,8 @@ namespace ts {
|
|||
case SyntaxKind.ParenthesizedType:
|
||||
case SyntaxKind.TypeOperator:
|
||||
return visitNode(cbNode, (<ParenthesizedTypeNode | TypeOperatorNode>node).type);
|
||||
case SyntaxKind.ReturnOperator:
|
||||
return visitNode(cbNode, (<ReturnOperatorNode>node).type);
|
||||
case SyntaxKind.IndexedAccessType:
|
||||
return visitNode(cbNode, (<IndexedAccessTypeNode>node).objectType) ||
|
||||
visitNode(cbNode, (<IndexedAccessTypeNode>node).indexType);
|
||||
|
@ -2115,7 +2118,6 @@ namespace ts {
|
|||
if (parseOptional(SyntaxKind.ColonToken)) {
|
||||
return parseType();
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
@ -2152,6 +2154,9 @@ namespace ts {
|
|||
|
||||
node.questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
|
||||
node.type = parseParameterType();
|
||||
if (parseOptional(SyntaxKind.AsKeyword)) {
|
||||
node.contextualType = parseType();
|
||||
}
|
||||
node.initializer = parseBindingElementInitializer(/*inParameter*/ true);
|
||||
|
||||
// Do not check for initializers in an ambient context for parameters. This is not
|
||||
|
@ -2611,7 +2616,23 @@ namespace ts {
|
|||
return type;
|
||||
}
|
||||
|
||||
function parseTypeOperator(operator: SyntaxKind.KeyOfKeyword) {
|
||||
function parseReturnOperator(operator: SyntaxKind.ReturnKeyword): TypeNode {
|
||||
const node = <ReturnOperatorNode>createNode(SyntaxKind.ReturnOperator);
|
||||
parseExpected(operator);
|
||||
node.operator = operator;
|
||||
node.type = parseReturnOperatorOrHigher();
|
||||
return finishNode(node);
|
||||
}
|
||||
|
||||
function parseReturnOperatorOrHigher(): TypeNode {
|
||||
switch (token()) {
|
||||
case SyntaxKind.ReturnKeyword:
|
||||
return parseReturnOperator(SyntaxKind.ReturnKeyword);
|
||||
}
|
||||
return parseTypeOperatorOrHigher();
|
||||
}
|
||||
|
||||
function parseTypeOperator(operator: SyntaxKind.KeyOfKeyword) {
|
||||
const node = <TypeOperatorNode>createNode(SyntaxKind.TypeOperator);
|
||||
parseExpected(operator);
|
||||
node.operator = operator;
|
||||
|
@ -2644,7 +2665,7 @@ namespace ts {
|
|||
}
|
||||
|
||||
function parseIntersectionTypeOrHigher(): TypeNode {
|
||||
return parseUnionOrIntersectionType(SyntaxKind.IntersectionType, parseTypeOperatorOrHigher, SyntaxKind.AmpersandToken);
|
||||
return parseUnionOrIntersectionType(SyntaxKind.IntersectionType, parseReturnOperatorOrHigher, SyntaxKind.AmpersandToken);
|
||||
}
|
||||
|
||||
function parseUnionTypeOrHigher(): TypeNode {
|
||||
|
|
|
@ -238,6 +238,7 @@
|
|||
ParenthesizedType,
|
||||
ThisType,
|
||||
TypeOperator,
|
||||
ReturnOperator,
|
||||
IndexedAccessType,
|
||||
MappedType,
|
||||
LiteralType,
|
||||
|
@ -665,6 +666,7 @@
|
|||
name: BindingName; // Declared parameter name
|
||||
questionToken?: QuestionToken; // Present on optional parameter
|
||||
type?: TypeNode; // Optional type annotation
|
||||
contextualType?: TypeNode; // Super-optional contextual type annotation
|
||||
initializer?: Expression; // Optional initializer
|
||||
}
|
||||
|
||||
|
@ -917,6 +919,12 @@
|
|||
type: TypeNode;
|
||||
}
|
||||
|
||||
export interface ReturnOperatorNode extends TypeNode {
|
||||
kind: SyntaxKind.ReturnOperator;
|
||||
operator: SyntaxKind.ReturnKeyword;
|
||||
type: TypeNode;
|
||||
}
|
||||
|
||||
export interface IndexedAccessTypeNode extends TypeNode {
|
||||
kind: SyntaxKind.IndexedAccessType;
|
||||
objectType: TypeNode;
|
||||
|
@ -2823,6 +2831,7 @@
|
|||
/* @internal */
|
||||
ContainsAnyFunctionType = 1 << 23, // Type is or contains object literal type
|
||||
NonPrimitive = 1 << 24, // intrinsic object type
|
||||
Return = 1 << 25, // Return type of callable (never for uncallable types)
|
||||
|
||||
/* @internal */
|
||||
Nullable = Undefined | Null,
|
||||
|
@ -2963,6 +2972,8 @@
|
|||
/* @internal */
|
||||
resolvedIndexType: IndexType;
|
||||
/* @internal */
|
||||
resolvedReturnType: ReturnType;
|
||||
/* @internal */
|
||||
resolvedBaseConstraint: Type;
|
||||
/* @internal */
|
||||
couldContainTypeVariables: boolean;
|
||||
|
@ -3030,6 +3041,8 @@
|
|||
resolvedBaseConstraint: Type;
|
||||
/* @internal */
|
||||
resolvedIndexType: IndexType;
|
||||
/* @internal */
|
||||
resolvedReturnType: ReturnType;
|
||||
}
|
||||
|
||||
// Type parameters (TypeFlags.TypeParameter)
|
||||
|
@ -3056,6 +3069,13 @@
|
|||
type: TypeVariable | UnionOrIntersectionType;
|
||||
}
|
||||
|
||||
// return T types (TypeFlags.Return)
|
||||
export interface ReturnType extends Type {
|
||||
type: TypeVariable | UnionOrIntersectionType;
|
||||
/* @internal */
|
||||
resolvedApparentType: Type;
|
||||
}
|
||||
|
||||
export const enum SignatureKind {
|
||||
Call,
|
||||
Construct,
|
||||
|
|
33
tests/baselines/reference/recursion.js
Normal file
33
tests/baselines/reference/recursion.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
//// [recursion.ts]
|
||||
let o = {
|
||||
p: 12,
|
||||
m(this: typeof o) {
|
||||
let x = this.m(); // x: number
|
||||
let y = this.p; // y: number
|
||||
return this.p;
|
||||
},
|
||||
m2() {
|
||||
return this.m() // this: any since it has no annotation
|
||||
}
|
||||
}
|
||||
|
||||
let x = o.m() // x: number
|
||||
let y = o.m2() // y: any
|
||||
let p = o.p // p: number
|
||||
|
||||
|
||||
//// [recursion.js]
|
||||
var o = {
|
||||
p: 12,
|
||||
m: function () {
|
||||
var x = this.m(); // x: number
|
||||
var y = this.p; // y: number
|
||||
return this.p;
|
||||
},
|
||||
m2: function () {
|
||||
return this.m(); // this: any since it has no annotation
|
||||
}
|
||||
};
|
||||
var x = o.m(); // x: number
|
||||
var y = o.m2(); // y: any
|
||||
var p = o.p; // p: number
|
55
tests/baselines/reference/recursion.symbols
Normal file
55
tests/baselines/reference/recursion.symbols
Normal file
|
@ -0,0 +1,55 @@
|
|||
=== tests/cases/compiler/recursion.ts ===
|
||||
let o = {
|
||||
>o : Symbol(o, Decl(recursion.ts, 0, 3))
|
||||
|
||||
p: 12,
|
||||
>p : Symbol(p, Decl(recursion.ts, 0, 9))
|
||||
|
||||
m(this: typeof o) {
|
||||
>m : Symbol(m, Decl(recursion.ts, 1, 10))
|
||||
>this : Symbol(this, Decl(recursion.ts, 2, 6))
|
||||
>o : Symbol(o, Decl(recursion.ts, 0, 3))
|
||||
|
||||
let x = this.m(); // x: number
|
||||
>x : Symbol(x, Decl(recursion.ts, 3, 11))
|
||||
>this.m : Symbol(m, Decl(recursion.ts, 1, 10))
|
||||
>this : Symbol(this, Decl(recursion.ts, 2, 6))
|
||||
>m : Symbol(m, Decl(recursion.ts, 1, 10))
|
||||
|
||||
let y = this.p; // y: number
|
||||
>y : Symbol(y, Decl(recursion.ts, 4, 11))
|
||||
>this.p : Symbol(p, Decl(recursion.ts, 0, 9))
|
||||
>this : Symbol(this, Decl(recursion.ts, 2, 6))
|
||||
>p : Symbol(p, Decl(recursion.ts, 0, 9))
|
||||
|
||||
return this.p;
|
||||
>this.p : Symbol(p, Decl(recursion.ts, 0, 9))
|
||||
>this : Symbol(this, Decl(recursion.ts, 2, 6))
|
||||
>p : Symbol(p, Decl(recursion.ts, 0, 9))
|
||||
|
||||
},
|
||||
m2() {
|
||||
>m2 : Symbol(m2, Decl(recursion.ts, 6, 6))
|
||||
|
||||
return this.m() // this: any since it has no annotation
|
||||
}
|
||||
}
|
||||
|
||||
let x = o.m() // x: number
|
||||
>x : Symbol(x, Decl(recursion.ts, 12, 3))
|
||||
>o.m : Symbol(m, Decl(recursion.ts, 1, 10))
|
||||
>o : Symbol(o, Decl(recursion.ts, 0, 3))
|
||||
>m : Symbol(m, Decl(recursion.ts, 1, 10))
|
||||
|
||||
let y = o.m2() // y: any
|
||||
>y : Symbol(y, Decl(recursion.ts, 13, 3))
|
||||
>o.m2 : Symbol(m2, Decl(recursion.ts, 6, 6))
|
||||
>o : Symbol(o, Decl(recursion.ts, 0, 3))
|
||||
>m2 : Symbol(m2, Decl(recursion.ts, 6, 6))
|
||||
|
||||
let p = o.p // p: number
|
||||
>p : Symbol(p, Decl(recursion.ts, 14, 3))
|
||||
>o.p : Symbol(p, Decl(recursion.ts, 0, 9))
|
||||
>o : Symbol(o, Decl(recursion.ts, 0, 3))
|
||||
>p : Symbol(p, Decl(recursion.ts, 0, 9))
|
||||
|
64
tests/baselines/reference/recursion.types
Normal file
64
tests/baselines/reference/recursion.types
Normal file
|
@ -0,0 +1,64 @@
|
|||
=== tests/cases/compiler/recursion.ts ===
|
||||
let o = {
|
||||
>o : { p: number; m(this: any): number; m2(): any; }
|
||||
>{ p: 12, m(this: typeof o) { let x = this.m(); // x: number let y = this.p; // y: number return this.p; }, m2() { return this.m() // this: any since it has no annotation }} : { p: number; m(this: any): number; m2(): any; }
|
||||
|
||||
p: 12,
|
||||
>p : number
|
||||
>12 : 12
|
||||
|
||||
m(this: typeof o) {
|
||||
>m : (this: { p: number; m(this: any): number; m2(): any; }) => number
|
||||
>this : { p: number; m(this: any): number; m2(): any; }
|
||||
>o : { p: number; m(this: any): number; m2(): any; }
|
||||
|
||||
let x = this.m(); // x: number
|
||||
>x : number
|
||||
>this.m() : number
|
||||
>this.m : (this: { p: number; m(this: any): number; m2(): any; }) => number
|
||||
>this : { p: number; m(this: any): number; m2(): any; }
|
||||
>m : (this: { p: number; m(this: any): number; m2(): any; }) => number
|
||||
|
||||
let y = this.p; // y: number
|
||||
>y : number
|
||||
>this.p : number
|
||||
>this : { p: number; m(this: any): number; m2(): any; }
|
||||
>p : number
|
||||
|
||||
return this.p;
|
||||
>this.p : number
|
||||
>this : { p: number; m(this: any): number; m2(): any; }
|
||||
>p : number
|
||||
|
||||
},
|
||||
m2() {
|
||||
>m2 : () => any
|
||||
|
||||
return this.m() // this: any since it has no annotation
|
||||
>this.m() : any
|
||||
>this.m : any
|
||||
>this : any
|
||||
>m : any
|
||||
}
|
||||
}
|
||||
|
||||
let x = o.m() // x: number
|
||||
>x : number
|
||||
>o.m() : number
|
||||
>o.m : (this: { p: number; m(this: any): number; m2(): any; }) => number
|
||||
>o : { p: number; m(this: any): number; m2(): any; }
|
||||
>m : (this: { p: number; m(this: any): number; m2(): any; }) => number
|
||||
|
||||
let y = o.m2() // y: any
|
||||
>y : any
|
||||
>o.m2() : any
|
||||
>o.m2 : () => any
|
||||
>o : { p: number; m(this: any): number; m2(): any; }
|
||||
>m2 : () => any
|
||||
|
||||
let p = o.p // p: number
|
||||
>p : number
|
||||
>o.p : number
|
||||
>o : { p: number; m(this: any): number; m2(): any; }
|
||||
>p : number
|
||||
|
85
tests/cases/compiler/recursion.ts
Normal file
85
tests/cases/compiler/recursion.ts
Normal file
|
@ -0,0 +1,85 @@
|
|||
// TODO: Assignability error when the contextual type of data is `U & V`
|
||||
declare function create<U, V, W>(
|
||||
x: {data: U, methods: V, properties: W} as
|
||||
{
|
||||
data: U,
|
||||
methods: { [s: string]: (this: U & V & Propertise<W>, ...args: any[]) => any },
|
||||
properties: { [s: string]: (this: U & V & Propertise<W>, ...args: any[]) => any }
|
||||
}): U & V & Propertise<W>;
|
||||
let vue = create({
|
||||
data: { x: 1 },
|
||||
methods: {
|
||||
m() { return 12 /*this.x*/ },
|
||||
m2() { return this.m() },
|
||||
m3() { return this.p },
|
||||
},
|
||||
properties: {
|
||||
p() { return 'foo' /*this.x*/ },
|
||||
p2() { return this.p },
|
||||
p3() { return this.m() },
|
||||
}
|
||||
});
|
||||
/**
|
||||
Problem: you need to fix U and V but also make them provide a contextual type that includes the *whole* type.
|
||||
But transformed, so the *whole* *transformed* type.
|
||||
|
||||
So here's an idea: an in and out type. One is used for type inference (to)
|
||||
and the other is used for contextual typing. Plus maybe type inference from? Not sure about that one.
|
||||
*/
|
||||
|
||||
|
||||
type Propertise<T> = { [K in keyof T]: return T[K] };
|
||||
type ExplicitVue<T extends { data, methods, properties }> = T['data'] & T['methods'] & Propertise<T['properties']>;
|
||||
|
||||
let options = {
|
||||
data: {
|
||||
a: 12,
|
||||
},
|
||||
methods: {
|
||||
m1(this: ExplicitVue<typeof options>) {
|
||||
this.a;
|
||||
this.m2();
|
||||
return this.a + this.p.length;
|
||||
},
|
||||
m2(this: ExplicitVue<typeof options>) {
|
||||
return this.m1();
|
||||
}
|
||||
},
|
||||
properties: {
|
||||
p() { return 'foo' }
|
||||
}
|
||||
}
|
||||
|
||||
let app: ExplicitVue<typeof options>;
|
||||
/*interface Vue<T> {
|
||||
data: any,
|
||||
methods: { [s: string]: (this: ExplicitVue, ...args: any[]) => any },
|
||||
properties: Propertise<{ [s: string]: (this: ExplicitVue, ...args: any[]) => any }>
|
||||
}
|
||||
declare function create<T>(options: Vue<T>): Vue<T>;
|
||||
create({
|
||||
data: { a: 12 },
|
||||
methods: {
|
||||
},
|
||||
properties: {
|
||||
}
|
||||
});
|
||||
*/
|
||||
/*
|
||||
let o = {
|
||||
p: 12,
|
||||
m(this: typeof o) {
|
||||
let x = this.m(); // x: number
|
||||
let y = this.p; // y: number
|
||||
return this.p;
|
||||
},
|
||||
m2() {
|
||||
return this.m() // this: any since it has no annotation
|
||||
}
|
||||
}
|
||||
|
||||
let x = o.m() // x: number
|
||||
let y = o.m2() // y: any
|
||||
let p = o.p // p: number
|
||||
|
||||
*/
|
Loading…
Reference in a new issue