Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
00f6819
Port port negated types
weswigham Aug 20, 2026
068f5f5
Relax comparable relation for negated types
weswigham Sep 3, 2026
af8cba7
Regenerate API enum values for negated types
weswigham Sep 9, 2026
ea014a1
Fix negated type smoke regressions and preserve guard compatibility
weswigham Sep 10, 2026
a952288
Add API
weswigham Sep 14, 2026
c913f73
Add missing contextual type breakdown
weswigham Sep 14, 2026
5660da1
Improvements to and better testing for optional props and fresh objec…
weswigham Sep 14, 2026
976af96
Fix compound assignment control flow wrt negated types, other small f…
weswigham Sep 16, 2026
2b33b77
Merge branch 'main' into port-negated-types
weswigham Sep 16, 2026
5cb8176
Merge branch 'main' into port-negated-types
weswigham Sep 17, 2026
7e70dfc
Lint bug, more behavior improvements
weswigham Sep 17, 2026
8e81de9
Merge fresh negations into regular union and intersection members
weswigham Sep 22, 2026
693a594
Defer negation reductions to better handle negations over self-refere…
weswigham Sep 23, 2026
775c55f
More deferal-related fixes
weswigham Sep 24, 2026
df8dd74
Dont use apparent types for negated constraint relationship checks
weswigham Sep 28, 2026
e741c14
Merge branch 'main' into weswigham/negated-types
weswigham Sep 29, 2026
614c854
Merge branch 'main' into weswigham/negated-types
weswigham Sep 29, 2026
fd347a9
Merge branch 'main' into weswigham/negated-types
weswigham Oct 19, 2026
a00b970
Merge branch 'main' into weswigham/negated-types
weswigham Oct 20, 2026
0c876d2
Add workaroud for distributive conditional <-> negated key assignability
weswigham Oct 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
13 changes: 13 additions & 0 deletions packages/typescript/src/api/async/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2610,6 +2610,11 @@ export class Checker {
return type.getNonNullableType();
}

/** Get the negation of a type. Always returns a type. */
async getNegatedType(type: Type): Promise<Type> {
return type.getNegatedType();
}

/**
* Get the type for a type node. Always returns a type; for type nodes whose
* type cannot be determined the checker yields the error type (use
Expand Down Expand Up @@ -3447,6 +3452,7 @@ class TypeObject implements Type {
private constraint: number | false;
private default: number | false;
private nonNullableType: number | false;
private negatedType: number | false;
private apparentType: number | false;
private reducedType: number | false;
private properties: readonly Symbol[] | false;
Expand Down Expand Up @@ -3526,6 +3532,7 @@ class TypeObject implements Type {
this.constraint = false;
this.default = false;
this.nonNullableType = false;
this.negatedType = false;
this.apparentType = false;
this.reducedType = false;
this.properties = false;
Expand Down Expand Up @@ -3581,6 +3588,12 @@ class TypeObject implements Type {
return result;
}

async getNegatedType(): Promise<Type> {
const result = await this.objectRegistry.fetchType(this, "getNegatedType", this.negatedType);
this.negatedType = result.id;
return result;
}

async getStringIndexType(): Promise<Type | undefined> {
if (this.stringIndexType === false) {
this.stringIndexType = await this.getStringIndexTypeWorker();
Expand Down
3 changes: 3 additions & 0 deletions packages/typescript/src/api/async/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@ export interface Type {
/** Get this type with `null` and `undefined` removed. */
getNonNullableType(): Promise<Type>;

/** Get the negation of this type. */
getNegatedType(): Promise<Type>;

/** Get this type's string index value type, if present. */
getStringIndexType(): Promise<Type | undefined>;

Expand Down
2 changes: 1 addition & 1 deletion packages/typescript/src/api/node/encoder.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ export function getNodeCommonData(node: Node): number {
case SyntaxKind.ObjectLiteralExpression:
return ((node as ObjectLiteralExpression).multiLine ? 1 : 0) << 24;
case SyntaxKind.TypeOperator:
return ((node as TypeOperatorNode).operator === SyntaxKind.ReadonlyKeyword ? 1 : (node as TypeOperatorNode).operator === SyntaxKind.UniqueKeyword ? 2 : 0) << 24;
return ((node as TypeOperatorNode).operator === SyntaxKind.ReadonlyKeyword ? 1 : (node as TypeOperatorNode).operator === SyntaxKind.UniqueKeyword ? 2 : (node as TypeOperatorNode).operator === SyntaxKind.NotKeyword ? 3 : 0) << 24;
case SyntaxKind.ImportAttributes:
return ((node as ImportAttributes).multiLine ? 1 : 0) << 24 | ((node as ImportAttributes).token === SyntaxKind.AssertKeyword ? 1 : 0) << 25;
case SyntaxKind.JsxText:
Expand Down
1 change: 1 addition & 0 deletions packages/typescript/src/api/node/node.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,7 @@ export class RemoteNode extends RemoteNodeBase implements Node {
const idx = (this.data >> 24) & 0x3;
if (idx === 1) return SyntaxKind.ReadonlyKeyword;
if (idx === 2) return SyntaxKind.UniqueKeyword;
if (idx === 3) return SyntaxKind.NotKeyword;
return SyntaxKind.KeyOfKeyword;
}
}
Expand Down
3 changes: 3 additions & 0 deletions packages/typescript/src/api/proto.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ export interface APIMethodInfo {
getApparentPropertiesOfType: APIMethod<GetTypePropertyParams, SymbolResponse[]>;
getApparentType: APIMethod<GetTypePropertyParams, TypeResponse>;
getReducedType: APIMethod<GetTypePropertyParams, TypeResponse>;
getNegatedType: APIMethod<GetTypePropertyParams, TypeResponse>;
getPropertyOfType: APIMethod<GetPropertyOfTypeParams, SymbolResponse | null>;
getTypeOfPropertyOfType: APIMethod<GetPropertyOfTypeParams, TypeResponse | null>;
getIndexInfoOfType: APIMethod<GetIndexInfoOfTypeParams, IndexInfoResponse | null>;
Expand Down Expand Up @@ -1222,6 +1223,7 @@ export interface BatchRequest {
| "getModeForResolutionAtIndex"
| "getModeForUsageLocation"
| "getNameTypeOfMappedType"
| "getNegatedType"
| "getNeverType"
| "getNonMissingTypeOfSymbol"
| "getNonNullableType"
Expand Down Expand Up @@ -1404,6 +1406,7 @@ export interface BatchResponse {
| "getModeForResolutionAtIndex"
| "getModeForUsageLocation"
| "getNameTypeOfMappedType"
| "getNegatedType"
| "getNeverType"
| "getNonMissingTypeOfSymbol"
| "getNonNullableType"
Expand Down
41 changes: 41 additions & 0 deletions packages/typescript/src/api/sync/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4941,6 +4941,24 @@ export class Checker {
);
}

/** Get the negation of a type. Always returns a type. */
get getNegatedType(): {
(type: Type): Type;
gen(type: Type): Generator<ProtocolRequest, Type, ProtocolResponse["result"]>;
} {
const owner = this;
return cacheGeneratorMethod(
owner,
"getNegatedType",
function (type: Type): Type {
return type.getNegatedType();
},
function* (type: Type): Generator<ProtocolRequest, Type, ProtocolResponse["result"]> {
return yield* type.getNegatedType.gen();
},
);
}

/**
* Get the type for a type node. Always returns a type; for type nodes whose
* type cannot be determined the checker yields the error type (use
Expand Down Expand Up @@ -7012,6 +7030,7 @@ class TypeObject implements Type {
private constraint: number | false;
private default: number | false;
private nonNullableType: number | false;
private negatedType: number | false;
private apparentType: number | false;
private reducedType: number | false;
private properties: readonly Symbol[] | false;
Expand Down Expand Up @@ -7091,6 +7110,7 @@ class TypeObject implements Type {
this.constraint = false;
this.default = false;
this.nonNullableType = false;
this.negatedType = false;
this.apparentType = false;
this.reducedType = false;
this.properties = false;
Expand Down Expand Up @@ -7251,6 +7271,27 @@ class TypeObject implements Type {
);
}

get getNegatedType(): {
(): Type;
gen(): Generator<ProtocolRequest, Type, ProtocolResponse["result"]>;
} {
const owner = this;
return cacheGeneratorMethod(
owner,
"getNegatedType",
function (): Type {
const result = owner.objectRegistry.fetchType(owner, "getNegatedType", owner.negatedType);
owner.negatedType = result.id;
return result;
},
function* (): Generator<ProtocolRequest, Type, ProtocolResponse["result"]> {
const result = yield* owner.objectRegistry.fetchType.gen(owner, "getNegatedType", owner.negatedType);
owner.negatedType = result.id;
return result;
},
);
}

get getStringIndexType(): {
(): Type | undefined;
gen(): Generator<ProtocolRequest, Type | undefined, ProtocolResponse["result"]>;
Expand Down
6 changes: 6 additions & 0 deletions packages/typescript/src/api/sync/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,12 @@ export interface Type {
gen(): Generator<ProtocolRequest, Type, ProtocolResponse["result"]>;
};

/** Get the negation of this type. */
getNegatedType: {
(): Type;
gen(): Generator<ProtocolRequest, Type, ProtocolResponse["result"]>;
};

/** Get this type's string index value type, if present. */
getStringIndexType: {
(): Type | undefined;
Expand Down
4 changes: 3 additions & 1 deletion packages/typescript/src/ast/ast.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ export type KeywordSyntaxKind =
| SyntaxKind.ModuleKeyword
| SyntaxKind.NamespaceKeyword
| SyntaxKind.NeverKeyword
| SyntaxKind.NotKeyword
| SyntaxKind.OutKeyword
| SyntaxKind.ReadonlyKeyword
| SyntaxKind.RequireKeyword
Expand Down Expand Up @@ -312,6 +313,7 @@ export type TokenSyntaxKind =
| SyntaxKind.ModuleKeyword
| SyntaxKind.NamespaceKeyword
| SyntaxKind.NeverKeyword
| SyntaxKind.NotKeyword
| SyntaxKind.OutKeyword
| SyntaxKind.ReadonlyKeyword
| SyntaxKind.RequireKeyword
Expand Down Expand Up @@ -964,7 +966,7 @@ export interface ConditionalTypeNode extends TypeNodeBase {
}
export interface TypeOperatorNode extends TypeNodeBase {
readonly kind: SyntaxKind.TypeOperator;
readonly operator: SyntaxKind.KeyOfKeyword | SyntaxKind.ReadonlyKeyword | SyntaxKind.UniqueKeyword;
readonly operator: SyntaxKind.KeyOfKeyword | SyntaxKind.ReadonlyKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.NotKeyword;
readonly type: TypeNode;
}
export interface InferTypeNode extends TypeNodeBase {
Expand Down
2 changes: 1 addition & 1 deletion packages/typescript/src/ast/factory.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4711,7 +4711,7 @@ export function createConditionalTypeNode(checkType: TypeNode, extendsType: Type
}) as unknown as ConditionalTypeNode;
}

export function createTypeOperatorNode(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.ReadonlyKeyword | SyntaxKind.UniqueKeyword, type: TypeNode): TypeOperatorNode {
export function createTypeOperatorNode(operator: SyntaxKind.KeyOfKeyword | SyntaxKind.ReadonlyKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.NotKeyword, type: TypeNode): TypeOperatorNode {
return new NodeObject(SyntaxKind.TypeOperator, {
operator,
type,
Expand Down
1 change: 1 addition & 0 deletions packages/typescript/src/enums/objectFlags.enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,5 @@ export enum ObjectFlags {
IsNeverIntersectionComputed = 1 << 25,
IsNeverIntersection = 1 << 26,
IsConstrainedTypeVariable = 1 << 27,
FreshNegated = 1 << 25,
}
1 change: 1 addition & 0 deletions packages/typescript/src/enums/objectFlags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,5 @@ export var ObjectFlags: any;
ObjectFlags[ObjectFlags["IsNeverIntersectionComputed"] = 33554432] = "IsNeverIntersectionComputed";
ObjectFlags[ObjectFlags["IsNeverIntersection"] = 67108864] = "IsNeverIntersection";
ObjectFlags[ObjectFlags["IsConstrainedTypeVariable"] = 134217728] = "IsConstrainedTypeVariable";
ObjectFlags[ObjectFlags["FreshNegated"] = 33554432] = "FreshNegated";
})(ObjectFlags || (ObjectFlags = {}));
Loading
Loading