Reverse mapped types with intersection constraint (#55811)

Co-authored-by: Mateusz Burzyński <mateuszburzynski@gmail.com>
Co-authored-by: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com>
This commit is contained in:
Andrea Simone Costa 2023-11-30 20:21:28 +01:00 committed by GitHub
parent 2c4cbd98fa
commit eb2046d046
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 1814 additions and 2 deletions

View File

@ -13647,6 +13647,23 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return instantiateType(instantiable, createTypeMapper([type.indexType, type.objectType], [getNumberLiteralType(0), createTupleType([replacement])]));
}
// If the original mapped type had an intersection constraint we extract its components,
// and we make an attempt to do so even if the intersection has been reduced to a union.
// This entire process allows us to possibly retrieve the filtering type literals.
// e.g. { [K in keyof U & ("a" | "b") ] } -> "a" | "b"
function getLimitedConstraint(type: ReverseMappedType) {
const constraint = getConstraintTypeFromMappedType(type.mappedType);
if (!(constraint.flags & TypeFlags.Union || constraint.flags & TypeFlags.Intersection)) {
return;
}
const origin = (constraint.flags & TypeFlags.Union) ? (constraint as UnionType).origin : (constraint as IntersectionType);
if (!origin || !(origin.flags & TypeFlags.Intersection)) {
return;
}
const limitedConstraint = getIntersectionType((origin as IntersectionType).types.filter(t => t !== type.constraintType));
return limitedConstraint !== neverType ? limitedConstraint : undefined;
}
function resolveReverseMappedTypeMembers(type: ReverseMappedType) {
const indexInfo = getIndexInfoOfType(type.source, stringType);
const modifiers = getMappedTypeModifiers(type.mappedType);
@ -13654,7 +13671,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
const optionalMask = modifiers & MappedTypeModifiers.IncludeOptional ? 0 : SymbolFlags.Optional;
const indexInfos = indexInfo ? [createIndexInfo(stringType, inferReverseMappedType(indexInfo.type, type.mappedType, type.constraintType), readonlyMask && indexInfo.isReadonly)] : emptyArray;
const members = createSymbolTable();
const limitedConstraint = getLimitedConstraint(type);
for (const prop of getPropertiesOfType(type.source)) {
// In case of a reverse mapped type with an intersection constraint, if we were able to
// extract the filtering type literals we skip those properties that are not assignable to them,
// because the extra properties wouldn't get through the application of the mapped type anyway
if (limitedConstraint) {
const propertyNameType = getLiteralTypeFromProperty(prop, TypeFlags.StringOrNumberLiteralOrUnique);
if (!isTypeAssignableTo(propertyNameType, limitedConstraint)) {
continue;
}
}
const checkFlags = CheckFlags.ReverseMapped | (readonlyMask && isReadonlySymbol(prop) ? CheckFlags.Readonly : 0);
const inferredProp = createSymbol(SymbolFlags.Property | prop.flags & optionalMask, prop.escapedName, checkFlags) as ReverseMappedSymbol;
inferredProp.declarations = prop.declarations;
@ -25665,9 +25692,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
function inferToMappedType(source: Type, target: MappedType, constraintType: Type): boolean {
if (constraintType.flags & TypeFlags.Union) {
if ((constraintType.flags & TypeFlags.Union) || (constraintType.flags & TypeFlags.Intersection)) {
let result = false;
for (const type of (constraintType as UnionType).types) {
for (const type of (constraintType as (UnionType | IntersectionType)).types) {
result = inferToMappedType(source, target, type) || result;
}
return result;

View File

@ -0,0 +1,225 @@
reverseMappedTypeIntersectionConstraint.ts(19,7): error TS2322: Type '"bar"' is not assignable to type '"foo"'.
reverseMappedTypeIntersectionConstraint.ts(32,3): error TS2353: Object literal may only specify known properties, and 'extra' does not exist in type '{ entry: "foo"; states: { a: { entry: "foo"; }; }; }'.
reverseMappedTypeIntersectionConstraint.ts(43,3): error TS2353: Object literal may only specify known properties, and 'z' does not exist in type '{ x: number; y: "y"; }'.
reverseMappedTypeIntersectionConstraint.ts(59,7): error TS2322: Type '{ [K in keyof T & keyof Stuff]: T[K]; }' is not assignable to type 'T'.
'{ [K in keyof T & keyof Stuff]: T[K]; }' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Stuff'.
reverseMappedTypeIntersectionConstraint.ts(63,49): error TS2353: Object literal may only specify known properties, and 'extra' does not exist in type '{ field: 1; anotherField: "a"; }'.
reverseMappedTypeIntersectionConstraint.ts(69,7): error TS2322: Type '{ [K in keyof T & keyof Stuff]: T[K]; }[]' is not assignable to type 'T[]'.
Type '{ [K in keyof T & keyof Stuff]: T[K]; }' is not assignable to type 'T'.
'{ [K in keyof T & keyof Stuff]: T[K]; }' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Stuff'.
reverseMappedTypeIntersectionConstraint.ts(74,36): error TS2353: Object literal may only specify known properties, and 'extra' does not exist in type '{ field: 1; anotherField: "a"; }'.
reverseMappedTypeIntersectionConstraint.ts(87,12): error TS2353: Object literal may only specify known properties, and 'y' does not exist in type '{ x: 1; }'.
reverseMappedTypeIntersectionConstraint.ts(98,12): error TS2353: Object literal may only specify known properties, and 'z' does not exist in type '{ x: 1; }'.
reverseMappedTypeIntersectionConstraint.ts(100,22): error TS2353: Object literal may only specify known properties, and 'z' does not exist in type '{ x: 1; y: "foo"; }'.
reverseMappedTypeIntersectionConstraint.ts(113,67): error TS2353: Object literal may only specify known properties, and 'extra' does not exist in type '{ prop: "foo"; nested: { prop: string; }; }'.
reverseMappedTypeIntersectionConstraint.ts(152,21): error TS2585: 'Promise' only refers to a type, but is being used as a value here. Do you need to change your target library? Try changing the 'lib' compiler option to es2015 or later.
reverseMappedTypeIntersectionConstraint.ts(164,3): error TS2353: Object literal may only specify known properties, and 'extra' does not exist in type '{ types: { actors: { src: "str"; logic: () => any; }; }; invoke: { readonly src: "str"; }; }'.
reverseMappedTypeIntersectionConstraint.ts(171,3): error TS2353: Object literal may only specify known properties, and 'extra' does not exist in type '{ invoke: { readonly src: "whatever"; }; }'.
==== reverseMappedTypeIntersectionConstraint.ts (14 errors) ====
type StateConfig<TAction extends string> = {
entry?: TAction
states?: Record<string, StateConfig<TAction>>;
};
type StateSchema = {
states?: Record<string, StateSchema>;
};
declare function createMachine<
TConfig extends StateConfig<TAction>,
TAction extends string = TConfig["entry"] extends string ? TConfig["entry"] : string,
>(config: { [K in keyof TConfig & keyof StateConfig<any>]: TConfig[K] }): [TAction, TConfig];
const inferredParams1 = createMachine({
entry: "foo",
states: {
a: {
entry: "bar",
~~~~~
!!! error TS2322: Type '"bar"' is not assignable to type '"foo"'.
!!! related TS6500 reverseMappedTypeIntersectionConstraint.ts:2:3: The expected type comes from property 'entry' which is declared here on type 'StateConfig<"foo">'
},
},
extra: 12,
});
const inferredParams2 = createMachine({
entry: "foo",
states: {
a: {
entry: "foo",
},
},
extra: 12,
~~~~~
!!! error TS2353: Object literal may only specify known properties, and 'extra' does not exist in type '{ entry: "foo"; states: { a: { entry: "foo"; }; }; }'.
});
// -----------------------------------------------------------------------------------------
const checkType = <T>() => <U extends T>(value: { [K in keyof U & keyof T]: U[K] }) => value;
const checked = checkType<{x: number, y: string}>()({
x: 1 as number,
y: "y",
z: "z", // undesirable property z is *not* allowed
~
!!! error TS2353: Object literal may only specify known properties, and 'z' does not exist in type '{ x: number; y: "y"; }'.
});
checked;
// -----------------------------------------------------------------------------------------
interface Stuff {
field: number;
anotherField: string;
}
function doStuffWithStuff<T extends Stuff>(s: { [K in keyof T & keyof Stuff]: T[K] } ): T {
if(Math.random() > 0.5) {
return s as T
} else {
return s
~~~~~~
!!! error TS2322: Type '{ [K in keyof T & keyof Stuff]: T[K]; }' is not assignable to type 'T'.
!!! error TS2322: '{ [K in keyof T & keyof Stuff]: T[K]; }' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Stuff'.
}
}
doStuffWithStuff({ field: 1, anotherField: 'a', extra: 123 })
~~~~~
!!! error TS2353: Object literal may only specify known properties, and 'extra' does not exist in type '{ field: 1; anotherField: "a"; }'.
function doStuffWithStuffArr<T extends Stuff>(arr: { [K in keyof T & keyof Stuff]: T[K] }[]): T[] {
if(Math.random() > 0.5) {
return arr as T[]
} else {
return arr
~~~~~~
!!! error TS2322: Type '{ [K in keyof T & keyof Stuff]: T[K]; }[]' is not assignable to type 'T[]'.
!!! error TS2322: Type '{ [K in keyof T & keyof Stuff]: T[K]; }' is not assignable to type 'T'.
!!! error TS2322: '{ [K in keyof T & keyof Stuff]: T[K]; }' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Stuff'.
}
}
doStuffWithStuffArr([
{ field: 1, anotherField: 'a', extra: 123 },
~~~~~
!!! error TS2353: Object literal may only specify known properties, and 'extra' does not exist in type '{ field: 1; anotherField: "a"; }'.
])
// -----------------------------------------------------------------------------------------
type XNumber = { x: number }
declare function foo<T extends XNumber>(props: {[K in keyof T & keyof XNumber]: T[K]}): void;
function bar(props: {x: number, y: string}) {
return foo(props); // no error because lack of excess property check by design
}
foo({x: 1, y: 'foo'});
~
!!! error TS2353: Object literal may only specify known properties, and 'y' does not exist in type '{ x: 1; }'.
foo({...{x: 1, y: 'foo'}}); // no error because lack of excess property check by design
// -----------------------------------------------------------------------------------------
type NoErrWithOptProps = { x: number, y?: string }
declare function baz<T extends NoErrWithOptProps>(props: {[K in keyof T & keyof NoErrWithOptProps]: T[K]}): void;
baz({x: 1});
baz({x: 1, z: 123});
~
!!! error TS2353: Object literal may only specify known properties, and 'z' does not exist in type '{ x: 1; }'.
baz({x: 1, y: 'foo'});
baz({x: 1, y: 'foo', z: 123});
~
!!! error TS2353: Object literal may only specify known properties, and 'z' does not exist in type '{ x: 1; y: "foo"; }'.
// -----------------------------------------------------------------------------------------
interface WithNestedProp {
prop: string;
nested: {
prop: string;
}
}
declare function withNestedProp<T extends WithNestedProp>(props: {[K in keyof T & keyof WithNestedProp]: T[K]}): T;
const wnp = withNestedProp({prop: 'foo', nested: { prop: 'bar' }, extra: 10 });
~~~~~
!!! error TS2353: Object literal may only specify known properties, and 'extra' does not exist in type '{ prop: "foo"; nested: { prop: string; }; }'.
// -----------------------------------------------------------------------------------------
type IsLiteralString<T extends string> = string extends T ? false : true;
type DeepWritable<T> = T extends Function ? T : { -readonly [K in keyof T]: DeepWritable<T[K]> }
interface ProvidedActor {
src: string;
logic: () => Promise<unknown>;
}
type DistributeActors<TActor> = TActor extends { src: infer TSrc }
? {
src: TSrc;
}
: never;
interface MachineConfig<TActor extends ProvidedActor> {
types?: {
actors?: TActor;
};
invoke: IsLiteralString<TActor["src"]> extends true
? DistributeActors<TActor>
: {
src: string;
};
}
type NoExtra<T> = {
[K in keyof T]: K extends keyof MachineConfig<any> ? T[K] : never
}
declare function createXMachine<
const TConfig extends MachineConfig<TActor>,
TActor extends ProvidedActor = TConfig extends { types: { actors: ProvidedActor} } ? TConfig["types"]["actors"] : ProvidedActor,
>(config: {[K in keyof MachineConfig<any> & keyof TConfig]: TConfig[K] }): TConfig;
const child = () => Promise.resolve("foo");
~~~~~~~
!!! error TS2585: 'Promise' only refers to a type, but is being used as a value here. Do you need to change your target library? Try changing the 'lib' compiler option to es2015 or later.
const config = createXMachine({
types: {} as {
actors: {
src: "str";
logic: typeof child;
};
},
invoke: {
src: "str",
},
extra: 10
~~~~~
!!! error TS2353: Object literal may only specify known properties, and 'extra' does not exist in type '{ types: { actors: { src: "str"; logic: () => any; }; }; invoke: { readonly src: "str"; }; }'.
});
const config2 = createXMachine({
invoke: {
src: "whatever",
},
extra: 10
~~~~~
!!! error TS2353: Object literal may only specify known properties, and 'extra' does not exist in type '{ invoke: { readonly src: "whatever"; }; }'.
});

View File

@ -0,0 +1,260 @@
//// [tests/cases/compiler/reverseMappedTypeIntersectionConstraint.ts] ////
//// [reverseMappedTypeIntersectionConstraint.ts]
type StateConfig<TAction extends string> = {
entry?: TAction
states?: Record<string, StateConfig<TAction>>;
};
type StateSchema = {
states?: Record<string, StateSchema>;
};
declare function createMachine<
TConfig extends StateConfig<TAction>,
TAction extends string = TConfig["entry"] extends string ? TConfig["entry"] : string,
>(config: { [K in keyof TConfig & keyof StateConfig<any>]: TConfig[K] }): [TAction, TConfig];
const inferredParams1 = createMachine({
entry: "foo",
states: {
a: {
entry: "bar",
},
},
extra: 12,
});
const inferredParams2 = createMachine({
entry: "foo",
states: {
a: {
entry: "foo",
},
},
extra: 12,
});
// -----------------------------------------------------------------------------------------
const checkType = <T>() => <U extends T>(value: { [K in keyof U & keyof T]: U[K] }) => value;
const checked = checkType<{x: number, y: string}>()({
x: 1 as number,
y: "y",
z: "z", // undesirable property z is *not* allowed
});
checked;
// -----------------------------------------------------------------------------------------
interface Stuff {
field: number;
anotherField: string;
}
function doStuffWithStuff<T extends Stuff>(s: { [K in keyof T & keyof Stuff]: T[K] } ): T {
if(Math.random() > 0.5) {
return s as T
} else {
return s
}
}
doStuffWithStuff({ field: 1, anotherField: 'a', extra: 123 })
function doStuffWithStuffArr<T extends Stuff>(arr: { [K in keyof T & keyof Stuff]: T[K] }[]): T[] {
if(Math.random() > 0.5) {
return arr as T[]
} else {
return arr
}
}
doStuffWithStuffArr([
{ field: 1, anotherField: 'a', extra: 123 },
])
// -----------------------------------------------------------------------------------------
type XNumber = { x: number }
declare function foo<T extends XNumber>(props: {[K in keyof T & keyof XNumber]: T[K]}): void;
function bar(props: {x: number, y: string}) {
return foo(props); // no error because lack of excess property check by design
}
foo({x: 1, y: 'foo'});
foo({...{x: 1, y: 'foo'}}); // no error because lack of excess property check by design
// -----------------------------------------------------------------------------------------
type NoErrWithOptProps = { x: number, y?: string }
declare function baz<T extends NoErrWithOptProps>(props: {[K in keyof T & keyof NoErrWithOptProps]: T[K]}): void;
baz({x: 1});
baz({x: 1, z: 123});
baz({x: 1, y: 'foo'});
baz({x: 1, y: 'foo', z: 123});
// -----------------------------------------------------------------------------------------
interface WithNestedProp {
prop: string;
nested: {
prop: string;
}
}
declare function withNestedProp<T extends WithNestedProp>(props: {[K in keyof T & keyof WithNestedProp]: T[K]}): T;
const wnp = withNestedProp({prop: 'foo', nested: { prop: 'bar' }, extra: 10 });
// -----------------------------------------------------------------------------------------
type IsLiteralString<T extends string> = string extends T ? false : true;
type DeepWritable<T> = T extends Function ? T : { -readonly [K in keyof T]: DeepWritable<T[K]> }
interface ProvidedActor {
src: string;
logic: () => Promise<unknown>;
}
type DistributeActors<TActor> = TActor extends { src: infer TSrc }
? {
src: TSrc;
}
: never;
interface MachineConfig<TActor extends ProvidedActor> {
types?: {
actors?: TActor;
};
invoke: IsLiteralString<TActor["src"]> extends true
? DistributeActors<TActor>
: {
src: string;
};
}
type NoExtra<T> = {
[K in keyof T]: K extends keyof MachineConfig<any> ? T[K] : never
}
declare function createXMachine<
const TConfig extends MachineConfig<TActor>,
TActor extends ProvidedActor = TConfig extends { types: { actors: ProvidedActor} } ? TConfig["types"]["actors"] : ProvidedActor,
>(config: {[K in keyof MachineConfig<any> & keyof TConfig]: TConfig[K] }): TConfig;
const child = () => Promise.resolve("foo");
const config = createXMachine({
types: {} as {
actors: {
src: "str";
logic: typeof child;
};
},
invoke: {
src: "str",
},
extra: 10
});
const config2 = createXMachine({
invoke: {
src: "whatever",
},
extra: 10
});
//// [reverseMappedTypeIntersectionConstraint.js]
"use strict";
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var inferredParams1 = createMachine({
entry: "foo",
states: {
a: {
entry: "bar",
},
},
extra: 12,
});
var inferredParams2 = createMachine({
entry: "foo",
states: {
a: {
entry: "foo",
},
},
extra: 12,
});
// -----------------------------------------------------------------------------------------
var checkType = function () { return function (value) { return value; }; };
var checked = checkType()({
x: 1,
y: "y",
z: "z", // undesirable property z is *not* allowed
});
checked;
function doStuffWithStuff(s) {
if (Math.random() > 0.5) {
return s;
}
else {
return s;
}
}
doStuffWithStuff({ field: 1, anotherField: 'a', extra: 123 });
function doStuffWithStuffArr(arr) {
if (Math.random() > 0.5) {
return arr;
}
else {
return arr;
}
}
doStuffWithStuffArr([
{ field: 1, anotherField: 'a', extra: 123 },
]);
function bar(props) {
return foo(props); // no error because lack of excess property check by design
}
foo({ x: 1, y: 'foo' });
foo(__assign({ x: 1, y: 'foo' })); // no error because lack of excess property check by design
baz({ x: 1 });
baz({ x: 1, z: 123 });
baz({ x: 1, y: 'foo' });
baz({ x: 1, y: 'foo', z: 123 });
var wnp = withNestedProp({ prop: 'foo', nested: { prop: 'bar' }, extra: 10 });
var child = function () { return Promise.resolve("foo"); };
var config = createXMachine({
types: {},
invoke: {
src: "str",
},
extra: 10
});
var config2 = createXMachine({
invoke: {
src: "whatever",
},
extra: 10
});

View File

@ -0,0 +1,491 @@
//// [tests/cases/compiler/reverseMappedTypeIntersectionConstraint.ts] ////
=== reverseMappedTypeIntersectionConstraint.ts ===
type StateConfig<TAction extends string> = {
>StateConfig : Symbol(StateConfig, Decl(reverseMappedTypeIntersectionConstraint.ts, 0, 0))
>TAction : Symbol(TAction, Decl(reverseMappedTypeIntersectionConstraint.ts, 0, 17))
entry?: TAction
>entry : Symbol(entry, Decl(reverseMappedTypeIntersectionConstraint.ts, 0, 44))
>TAction : Symbol(TAction, Decl(reverseMappedTypeIntersectionConstraint.ts, 0, 17))
states?: Record<string, StateConfig<TAction>>;
>states : Symbol(states, Decl(reverseMappedTypeIntersectionConstraint.ts, 1, 17))
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
>StateConfig : Symbol(StateConfig, Decl(reverseMappedTypeIntersectionConstraint.ts, 0, 0))
>TAction : Symbol(TAction, Decl(reverseMappedTypeIntersectionConstraint.ts, 0, 17))
};
type StateSchema = {
>StateSchema : Symbol(StateSchema, Decl(reverseMappedTypeIntersectionConstraint.ts, 3, 2))
states?: Record<string, StateSchema>;
>states : Symbol(states, Decl(reverseMappedTypeIntersectionConstraint.ts, 5, 20))
>Record : Symbol(Record, Decl(lib.es5.d.ts, --, --))
>StateSchema : Symbol(StateSchema, Decl(reverseMappedTypeIntersectionConstraint.ts, 3, 2))
};
declare function createMachine<
>createMachine : Symbol(createMachine, Decl(reverseMappedTypeIntersectionConstraint.ts, 7, 2))
TConfig extends StateConfig<TAction>,
>TConfig : Symbol(TConfig, Decl(reverseMappedTypeIntersectionConstraint.ts, 9, 31))
>StateConfig : Symbol(StateConfig, Decl(reverseMappedTypeIntersectionConstraint.ts, 0, 0))
>TAction : Symbol(TAction, Decl(reverseMappedTypeIntersectionConstraint.ts, 10, 39))
TAction extends string = TConfig["entry"] extends string ? TConfig["entry"] : string,
>TAction : Symbol(TAction, Decl(reverseMappedTypeIntersectionConstraint.ts, 10, 39))
>TConfig : Symbol(TConfig, Decl(reverseMappedTypeIntersectionConstraint.ts, 9, 31))
>TConfig : Symbol(TConfig, Decl(reverseMappedTypeIntersectionConstraint.ts, 9, 31))
>(config: { [K in keyof TConfig & keyof StateConfig<any>]: TConfig[K] }): [TAction, TConfig];
>config : Symbol(config, Decl(reverseMappedTypeIntersectionConstraint.ts, 12, 2))
>K : Symbol(K, Decl(reverseMappedTypeIntersectionConstraint.ts, 12, 13))
>TConfig : Symbol(TConfig, Decl(reverseMappedTypeIntersectionConstraint.ts, 9, 31))
>StateConfig : Symbol(StateConfig, Decl(reverseMappedTypeIntersectionConstraint.ts, 0, 0))
>TConfig : Symbol(TConfig, Decl(reverseMappedTypeIntersectionConstraint.ts, 9, 31))
>K : Symbol(K, Decl(reverseMappedTypeIntersectionConstraint.ts, 12, 13))
>TAction : Symbol(TAction, Decl(reverseMappedTypeIntersectionConstraint.ts, 10, 39))
>TConfig : Symbol(TConfig, Decl(reverseMappedTypeIntersectionConstraint.ts, 9, 31))
const inferredParams1 = createMachine({
>inferredParams1 : Symbol(inferredParams1, Decl(reverseMappedTypeIntersectionConstraint.ts, 14, 5))
>createMachine : Symbol(createMachine, Decl(reverseMappedTypeIntersectionConstraint.ts, 7, 2))
entry: "foo",
>entry : Symbol(entry, Decl(reverseMappedTypeIntersectionConstraint.ts, 14, 39))
states: {
>states : Symbol(states, Decl(reverseMappedTypeIntersectionConstraint.ts, 15, 15))
a: {
>a : Symbol(a, Decl(reverseMappedTypeIntersectionConstraint.ts, 16, 11))
entry: "bar",
>entry : Symbol(entry, Decl(reverseMappedTypeIntersectionConstraint.ts, 17, 8))
},
},
extra: 12,
>extra : Symbol(extra, Decl(reverseMappedTypeIntersectionConstraint.ts, 20, 4))
});
const inferredParams2 = createMachine({
>inferredParams2 : Symbol(inferredParams2, Decl(reverseMappedTypeIntersectionConstraint.ts, 24, 5))
>createMachine : Symbol(createMachine, Decl(reverseMappedTypeIntersectionConstraint.ts, 7, 2))
entry: "foo",
>entry : Symbol(entry, Decl(reverseMappedTypeIntersectionConstraint.ts, 24, 39))
states: {
>states : Symbol(states, Decl(reverseMappedTypeIntersectionConstraint.ts, 25, 15))
a: {
>a : Symbol(a, Decl(reverseMappedTypeIntersectionConstraint.ts, 26, 11))
entry: "foo",
>entry : Symbol(entry, Decl(reverseMappedTypeIntersectionConstraint.ts, 27, 8))
},
},
extra: 12,
>extra : Symbol(extra, Decl(reverseMappedTypeIntersectionConstraint.ts, 30, 4))
});
// -----------------------------------------------------------------------------------------
const checkType = <T>() => <U extends T>(value: { [K in keyof U & keyof T]: U[K] }) => value;
>checkType : Symbol(checkType, Decl(reverseMappedTypeIntersectionConstraint.ts, 37, 5))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 37, 19))
>U : Symbol(U, Decl(reverseMappedTypeIntersectionConstraint.ts, 37, 28))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 37, 19))
>value : Symbol(value, Decl(reverseMappedTypeIntersectionConstraint.ts, 37, 41))
>K : Symbol(K, Decl(reverseMappedTypeIntersectionConstraint.ts, 37, 51))
>U : Symbol(U, Decl(reverseMappedTypeIntersectionConstraint.ts, 37, 28))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 37, 19))
>U : Symbol(U, Decl(reverseMappedTypeIntersectionConstraint.ts, 37, 28))
>K : Symbol(K, Decl(reverseMappedTypeIntersectionConstraint.ts, 37, 51))
>value : Symbol(value, Decl(reverseMappedTypeIntersectionConstraint.ts, 37, 41))
const checked = checkType<{x: number, y: string}>()({
>checked : Symbol(checked, Decl(reverseMappedTypeIntersectionConstraint.ts, 39, 5))
>checkType : Symbol(checkType, Decl(reverseMappedTypeIntersectionConstraint.ts, 37, 5))
>x : Symbol(x, Decl(reverseMappedTypeIntersectionConstraint.ts, 39, 27))
>y : Symbol(y, Decl(reverseMappedTypeIntersectionConstraint.ts, 39, 37))
x: 1 as number,
>x : Symbol(x, Decl(reverseMappedTypeIntersectionConstraint.ts, 39, 53))
y: "y",
>y : Symbol(y, Decl(reverseMappedTypeIntersectionConstraint.ts, 40, 17))
z: "z", // undesirable property z is *not* allowed
>z : Symbol(z, Decl(reverseMappedTypeIntersectionConstraint.ts, 41, 9))
});
checked;
>checked : Symbol(checked, Decl(reverseMappedTypeIntersectionConstraint.ts, 39, 5))
// -----------------------------------------------------------------------------------------
interface Stuff {
>Stuff : Symbol(Stuff, Decl(reverseMappedTypeIntersectionConstraint.ts, 45, 8))
field: number;
>field : Symbol(Stuff.field, Decl(reverseMappedTypeIntersectionConstraint.ts, 49, 17))
anotherField: string;
>anotherField : Symbol(Stuff.anotherField, Decl(reverseMappedTypeIntersectionConstraint.ts, 50, 18))
}
function doStuffWithStuff<T extends Stuff>(s: { [K in keyof T & keyof Stuff]: T[K] } ): T {
>doStuffWithStuff : Symbol(doStuffWithStuff, Decl(reverseMappedTypeIntersectionConstraint.ts, 52, 1))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 54, 26))
>Stuff : Symbol(Stuff, Decl(reverseMappedTypeIntersectionConstraint.ts, 45, 8))
>s : Symbol(s, Decl(reverseMappedTypeIntersectionConstraint.ts, 54, 43))
>K : Symbol(K, Decl(reverseMappedTypeIntersectionConstraint.ts, 54, 49))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 54, 26))
>Stuff : Symbol(Stuff, Decl(reverseMappedTypeIntersectionConstraint.ts, 45, 8))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 54, 26))
>K : Symbol(K, Decl(reverseMappedTypeIntersectionConstraint.ts, 54, 49))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 54, 26))
if(Math.random() > 0.5) {
>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --))
>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --))
return s as T
>s : Symbol(s, Decl(reverseMappedTypeIntersectionConstraint.ts, 54, 43))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 54, 26))
} else {
return s
>s : Symbol(s, Decl(reverseMappedTypeIntersectionConstraint.ts, 54, 43))
}
}
doStuffWithStuff({ field: 1, anotherField: 'a', extra: 123 })
>doStuffWithStuff : Symbol(doStuffWithStuff, Decl(reverseMappedTypeIntersectionConstraint.ts, 52, 1))
>field : Symbol(field, Decl(reverseMappedTypeIntersectionConstraint.ts, 62, 18))
>anotherField : Symbol(anotherField, Decl(reverseMappedTypeIntersectionConstraint.ts, 62, 28))
>extra : Symbol(extra, Decl(reverseMappedTypeIntersectionConstraint.ts, 62, 47))
function doStuffWithStuffArr<T extends Stuff>(arr: { [K in keyof T & keyof Stuff]: T[K] }[]): T[] {
>doStuffWithStuffArr : Symbol(doStuffWithStuffArr, Decl(reverseMappedTypeIntersectionConstraint.ts, 62, 61))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 64, 29))
>Stuff : Symbol(Stuff, Decl(reverseMappedTypeIntersectionConstraint.ts, 45, 8))
>arr : Symbol(arr, Decl(reverseMappedTypeIntersectionConstraint.ts, 64, 46))
>K : Symbol(K, Decl(reverseMappedTypeIntersectionConstraint.ts, 64, 54))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 64, 29))
>Stuff : Symbol(Stuff, Decl(reverseMappedTypeIntersectionConstraint.ts, 45, 8))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 64, 29))
>K : Symbol(K, Decl(reverseMappedTypeIntersectionConstraint.ts, 64, 54))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 64, 29))
if(Math.random() > 0.5) {
>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --))
>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --))
return arr as T[]
>arr : Symbol(arr, Decl(reverseMappedTypeIntersectionConstraint.ts, 64, 46))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 64, 29))
} else {
return arr
>arr : Symbol(arr, Decl(reverseMappedTypeIntersectionConstraint.ts, 64, 46))
}
}
doStuffWithStuffArr([
>doStuffWithStuffArr : Symbol(doStuffWithStuffArr, Decl(reverseMappedTypeIntersectionConstraint.ts, 62, 61))
{ field: 1, anotherField: 'a', extra: 123 },
>field : Symbol(field, Decl(reverseMappedTypeIntersectionConstraint.ts, 73, 5))
>anotherField : Symbol(anotherField, Decl(reverseMappedTypeIntersectionConstraint.ts, 73, 15))
>extra : Symbol(extra, Decl(reverseMappedTypeIntersectionConstraint.ts, 73, 34))
])
// -----------------------------------------------------------------------------------------
type XNumber = { x: number }
>XNumber : Symbol(XNumber, Decl(reverseMappedTypeIntersectionConstraint.ts, 74, 2))
>x : Symbol(x, Decl(reverseMappedTypeIntersectionConstraint.ts, 78, 16))
declare function foo<T extends XNumber>(props: {[K in keyof T & keyof XNumber]: T[K]}): void;
>foo : Symbol(foo, Decl(reverseMappedTypeIntersectionConstraint.ts, 78, 28))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 80, 21))
>XNumber : Symbol(XNumber, Decl(reverseMappedTypeIntersectionConstraint.ts, 74, 2))
>props : Symbol(props, Decl(reverseMappedTypeIntersectionConstraint.ts, 80, 40))
>K : Symbol(K, Decl(reverseMappedTypeIntersectionConstraint.ts, 80, 49))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 80, 21))
>XNumber : Symbol(XNumber, Decl(reverseMappedTypeIntersectionConstraint.ts, 74, 2))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 80, 21))
>K : Symbol(K, Decl(reverseMappedTypeIntersectionConstraint.ts, 80, 49))
function bar(props: {x: number, y: string}) {
>bar : Symbol(bar, Decl(reverseMappedTypeIntersectionConstraint.ts, 80, 93))
>props : Symbol(props, Decl(reverseMappedTypeIntersectionConstraint.ts, 82, 13))
>x : Symbol(x, Decl(reverseMappedTypeIntersectionConstraint.ts, 82, 21))
>y : Symbol(y, Decl(reverseMappedTypeIntersectionConstraint.ts, 82, 31))
return foo(props); // no error because lack of excess property check by design
>foo : Symbol(foo, Decl(reverseMappedTypeIntersectionConstraint.ts, 78, 28))
>props : Symbol(props, Decl(reverseMappedTypeIntersectionConstraint.ts, 82, 13))
}
foo({x: 1, y: 'foo'});
>foo : Symbol(foo, Decl(reverseMappedTypeIntersectionConstraint.ts, 78, 28))
>x : Symbol(x, Decl(reverseMappedTypeIntersectionConstraint.ts, 86, 5))
>y : Symbol(y, Decl(reverseMappedTypeIntersectionConstraint.ts, 86, 10))
foo({...{x: 1, y: 'foo'}}); // no error because lack of excess property check by design
>foo : Symbol(foo, Decl(reverseMappedTypeIntersectionConstraint.ts, 78, 28))
>x : Symbol(x, Decl(reverseMappedTypeIntersectionConstraint.ts, 88, 9))
>y : Symbol(y, Decl(reverseMappedTypeIntersectionConstraint.ts, 88, 14))
// -----------------------------------------------------------------------------------------
type NoErrWithOptProps = { x: number, y?: string }
>NoErrWithOptProps : Symbol(NoErrWithOptProps, Decl(reverseMappedTypeIntersectionConstraint.ts, 88, 27))
>x : Symbol(x, Decl(reverseMappedTypeIntersectionConstraint.ts, 92, 26))
>y : Symbol(y, Decl(reverseMappedTypeIntersectionConstraint.ts, 92, 37))
declare function baz<T extends NoErrWithOptProps>(props: {[K in keyof T & keyof NoErrWithOptProps]: T[K]}): void;
>baz : Symbol(baz, Decl(reverseMappedTypeIntersectionConstraint.ts, 92, 50))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 94, 21))
>NoErrWithOptProps : Symbol(NoErrWithOptProps, Decl(reverseMappedTypeIntersectionConstraint.ts, 88, 27))
>props : Symbol(props, Decl(reverseMappedTypeIntersectionConstraint.ts, 94, 50))
>K : Symbol(K, Decl(reverseMappedTypeIntersectionConstraint.ts, 94, 59))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 94, 21))
>NoErrWithOptProps : Symbol(NoErrWithOptProps, Decl(reverseMappedTypeIntersectionConstraint.ts, 88, 27))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 94, 21))
>K : Symbol(K, Decl(reverseMappedTypeIntersectionConstraint.ts, 94, 59))
baz({x: 1});
>baz : Symbol(baz, Decl(reverseMappedTypeIntersectionConstraint.ts, 92, 50))
>x : Symbol(x, Decl(reverseMappedTypeIntersectionConstraint.ts, 96, 5))
baz({x: 1, z: 123});
>baz : Symbol(baz, Decl(reverseMappedTypeIntersectionConstraint.ts, 92, 50))
>x : Symbol(x, Decl(reverseMappedTypeIntersectionConstraint.ts, 97, 5))
>z : Symbol(z, Decl(reverseMappedTypeIntersectionConstraint.ts, 97, 10))
baz({x: 1, y: 'foo'});
>baz : Symbol(baz, Decl(reverseMappedTypeIntersectionConstraint.ts, 92, 50))
>x : Symbol(x, Decl(reverseMappedTypeIntersectionConstraint.ts, 98, 5))
>y : Symbol(y, Decl(reverseMappedTypeIntersectionConstraint.ts, 98, 10))
baz({x: 1, y: 'foo', z: 123});
>baz : Symbol(baz, Decl(reverseMappedTypeIntersectionConstraint.ts, 92, 50))
>x : Symbol(x, Decl(reverseMappedTypeIntersectionConstraint.ts, 99, 5))
>y : Symbol(y, Decl(reverseMappedTypeIntersectionConstraint.ts, 99, 10))
>z : Symbol(z, Decl(reverseMappedTypeIntersectionConstraint.ts, 99, 20))
// -----------------------------------------------------------------------------------------
interface WithNestedProp {
>WithNestedProp : Symbol(WithNestedProp, Decl(reverseMappedTypeIntersectionConstraint.ts, 99, 30))
prop: string;
>prop : Symbol(WithNestedProp.prop, Decl(reverseMappedTypeIntersectionConstraint.ts, 103, 26))
nested: {
>nested : Symbol(WithNestedProp.nested, Decl(reverseMappedTypeIntersectionConstraint.ts, 104, 15))
prop: string;
>prop : Symbol(prop, Decl(reverseMappedTypeIntersectionConstraint.ts, 105, 11))
}
}
declare function withNestedProp<T extends WithNestedProp>(props: {[K in keyof T & keyof WithNestedProp]: T[K]}): T;
>withNestedProp : Symbol(withNestedProp, Decl(reverseMappedTypeIntersectionConstraint.ts, 108, 1))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 110, 32))
>WithNestedProp : Symbol(WithNestedProp, Decl(reverseMappedTypeIntersectionConstraint.ts, 99, 30))
>props : Symbol(props, Decl(reverseMappedTypeIntersectionConstraint.ts, 110, 58))
>K : Symbol(K, Decl(reverseMappedTypeIntersectionConstraint.ts, 110, 67))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 110, 32))
>WithNestedProp : Symbol(WithNestedProp, Decl(reverseMappedTypeIntersectionConstraint.ts, 99, 30))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 110, 32))
>K : Symbol(K, Decl(reverseMappedTypeIntersectionConstraint.ts, 110, 67))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 110, 32))
const wnp = withNestedProp({prop: 'foo', nested: { prop: 'bar' }, extra: 10 });
>wnp : Symbol(wnp, Decl(reverseMappedTypeIntersectionConstraint.ts, 112, 5))
>withNestedProp : Symbol(withNestedProp, Decl(reverseMappedTypeIntersectionConstraint.ts, 108, 1))
>prop : Symbol(prop, Decl(reverseMappedTypeIntersectionConstraint.ts, 112, 28))
>nested : Symbol(nested, Decl(reverseMappedTypeIntersectionConstraint.ts, 112, 40))
>prop : Symbol(prop, Decl(reverseMappedTypeIntersectionConstraint.ts, 112, 50))
>extra : Symbol(extra, Decl(reverseMappedTypeIntersectionConstraint.ts, 112, 65))
// -----------------------------------------------------------------------------------------
type IsLiteralString<T extends string> = string extends T ? false : true;
>IsLiteralString : Symbol(IsLiteralString, Decl(reverseMappedTypeIntersectionConstraint.ts, 112, 79))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 116, 21))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 116, 21))
type DeepWritable<T> = T extends Function ? T : { -readonly [K in keyof T]: DeepWritable<T[K]> }
>DeepWritable : Symbol(DeepWritable, Decl(reverseMappedTypeIntersectionConstraint.ts, 116, 73))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 118, 18))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 118, 18))
>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 118, 18))
>K : Symbol(K, Decl(reverseMappedTypeIntersectionConstraint.ts, 118, 61))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 118, 18))
>DeepWritable : Symbol(DeepWritable, Decl(reverseMappedTypeIntersectionConstraint.ts, 116, 73))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 118, 18))
>K : Symbol(K, Decl(reverseMappedTypeIntersectionConstraint.ts, 118, 61))
interface ProvidedActor {
>ProvidedActor : Symbol(ProvidedActor, Decl(reverseMappedTypeIntersectionConstraint.ts, 118, 96))
src: string;
>src : Symbol(ProvidedActor.src, Decl(reverseMappedTypeIntersectionConstraint.ts, 120, 25))
logic: () => Promise<unknown>;
>logic : Symbol(ProvidedActor.logic, Decl(reverseMappedTypeIntersectionConstraint.ts, 121, 14))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --))
}
type DistributeActors<TActor> = TActor extends { src: infer TSrc }
>DistributeActors : Symbol(DistributeActors, Decl(reverseMappedTypeIntersectionConstraint.ts, 123, 1))
>TActor : Symbol(TActor, Decl(reverseMappedTypeIntersectionConstraint.ts, 125, 22))
>TActor : Symbol(TActor, Decl(reverseMappedTypeIntersectionConstraint.ts, 125, 22))
>src : Symbol(src, Decl(reverseMappedTypeIntersectionConstraint.ts, 125, 48))
>TSrc : Symbol(TSrc, Decl(reverseMappedTypeIntersectionConstraint.ts, 125, 59))
? {
src: TSrc;
>src : Symbol(src, Decl(reverseMappedTypeIntersectionConstraint.ts, 126, 5))
>TSrc : Symbol(TSrc, Decl(reverseMappedTypeIntersectionConstraint.ts, 125, 59))
}
: never;
interface MachineConfig<TActor extends ProvidedActor> {
>MachineConfig : Symbol(MachineConfig, Decl(reverseMappedTypeIntersectionConstraint.ts, 129, 10))
>TActor : Symbol(TActor, Decl(reverseMappedTypeIntersectionConstraint.ts, 131, 24))
>ProvidedActor : Symbol(ProvidedActor, Decl(reverseMappedTypeIntersectionConstraint.ts, 118, 96))
types?: {
>types : Symbol(MachineConfig.types, Decl(reverseMappedTypeIntersectionConstraint.ts, 131, 55))
actors?: TActor;
>actors : Symbol(actors, Decl(reverseMappedTypeIntersectionConstraint.ts, 132, 11))
>TActor : Symbol(TActor, Decl(reverseMappedTypeIntersectionConstraint.ts, 131, 24))
};
invoke: IsLiteralString<TActor["src"]> extends true
>invoke : Symbol(MachineConfig.invoke, Decl(reverseMappedTypeIntersectionConstraint.ts, 134, 4))
>IsLiteralString : Symbol(IsLiteralString, Decl(reverseMappedTypeIntersectionConstraint.ts, 112, 79))
>TActor : Symbol(TActor, Decl(reverseMappedTypeIntersectionConstraint.ts, 131, 24))
? DistributeActors<TActor>
>DistributeActors : Symbol(DistributeActors, Decl(reverseMappedTypeIntersectionConstraint.ts, 123, 1))
>TActor : Symbol(TActor, Decl(reverseMappedTypeIntersectionConstraint.ts, 131, 24))
: {
src: string;
>src : Symbol(src, Decl(reverseMappedTypeIntersectionConstraint.ts, 137, 7))
};
}
type NoExtra<T> = {
>NoExtra : Symbol(NoExtra, Decl(reverseMappedTypeIntersectionConstraint.ts, 140, 1))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 142, 13))
[K in keyof T]: K extends keyof MachineConfig<any> ? T[K] : never
>K : Symbol(K, Decl(reverseMappedTypeIntersectionConstraint.ts, 143, 3))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 142, 13))
>K : Symbol(K, Decl(reverseMappedTypeIntersectionConstraint.ts, 143, 3))
>MachineConfig : Symbol(MachineConfig, Decl(reverseMappedTypeIntersectionConstraint.ts, 129, 10))
>T : Symbol(T, Decl(reverseMappedTypeIntersectionConstraint.ts, 142, 13))
>K : Symbol(K, Decl(reverseMappedTypeIntersectionConstraint.ts, 143, 3))
}
declare function createXMachine<
>createXMachine : Symbol(createXMachine, Decl(reverseMappedTypeIntersectionConstraint.ts, 144, 1))
const TConfig extends MachineConfig<TActor>,
>TConfig : Symbol(TConfig, Decl(reverseMappedTypeIntersectionConstraint.ts, 146, 32))
>MachineConfig : Symbol(MachineConfig, Decl(reverseMappedTypeIntersectionConstraint.ts, 129, 10))
>TActor : Symbol(TActor, Decl(reverseMappedTypeIntersectionConstraint.ts, 147, 46))
TActor extends ProvidedActor = TConfig extends { types: { actors: ProvidedActor} } ? TConfig["types"]["actors"] : ProvidedActor,
>TActor : Symbol(TActor, Decl(reverseMappedTypeIntersectionConstraint.ts, 147, 46))
>ProvidedActor : Symbol(ProvidedActor, Decl(reverseMappedTypeIntersectionConstraint.ts, 118, 96))
>TConfig : Symbol(TConfig, Decl(reverseMappedTypeIntersectionConstraint.ts, 146, 32))
>types : Symbol(types, Decl(reverseMappedTypeIntersectionConstraint.ts, 148, 50))
>actors : Symbol(actors, Decl(reverseMappedTypeIntersectionConstraint.ts, 148, 59))
>ProvidedActor : Symbol(ProvidedActor, Decl(reverseMappedTypeIntersectionConstraint.ts, 118, 96))
>TConfig : Symbol(TConfig, Decl(reverseMappedTypeIntersectionConstraint.ts, 146, 32))
>ProvidedActor : Symbol(ProvidedActor, Decl(reverseMappedTypeIntersectionConstraint.ts, 118, 96))
>(config: {[K in keyof MachineConfig<any> & keyof TConfig]: TConfig[K] }): TConfig;
>config : Symbol(config, Decl(reverseMappedTypeIntersectionConstraint.ts, 149, 2))
>K : Symbol(K, Decl(reverseMappedTypeIntersectionConstraint.ts, 149, 12))
>MachineConfig : Symbol(MachineConfig, Decl(reverseMappedTypeIntersectionConstraint.ts, 129, 10))
>TConfig : Symbol(TConfig, Decl(reverseMappedTypeIntersectionConstraint.ts, 146, 32))
>TConfig : Symbol(TConfig, Decl(reverseMappedTypeIntersectionConstraint.ts, 146, 32))
>K : Symbol(K, Decl(reverseMappedTypeIntersectionConstraint.ts, 149, 12))
>TConfig : Symbol(TConfig, Decl(reverseMappedTypeIntersectionConstraint.ts, 146, 32))
const child = () => Promise.resolve("foo");
>child : Symbol(child, Decl(reverseMappedTypeIntersectionConstraint.ts, 151, 5))
const config = createXMachine({
>config : Symbol(config, Decl(reverseMappedTypeIntersectionConstraint.ts, 153, 5))
>createXMachine : Symbol(createXMachine, Decl(reverseMappedTypeIntersectionConstraint.ts, 144, 1))
types: {} as {
>types : Symbol(types, Decl(reverseMappedTypeIntersectionConstraint.ts, 153, 31))
actors: {
>actors : Symbol(actors, Decl(reverseMappedTypeIntersectionConstraint.ts, 154, 16))
src: "str";
>src : Symbol(src, Decl(reverseMappedTypeIntersectionConstraint.ts, 155, 13))
logic: typeof child;
>logic : Symbol(logic, Decl(reverseMappedTypeIntersectionConstraint.ts, 156, 17))
>child : Symbol(child, Decl(reverseMappedTypeIntersectionConstraint.ts, 151, 5))
};
},
invoke: {
>invoke : Symbol(invoke, Decl(reverseMappedTypeIntersectionConstraint.ts, 159, 4))
src: "str",
>src : Symbol(src, Decl(reverseMappedTypeIntersectionConstraint.ts, 160, 11))
},
extra: 10
>extra : Symbol(extra, Decl(reverseMappedTypeIntersectionConstraint.ts, 162, 4))
});
const config2 = createXMachine({
>config2 : Symbol(config2, Decl(reverseMappedTypeIntersectionConstraint.ts, 166, 5))
>createXMachine : Symbol(createXMachine, Decl(reverseMappedTypeIntersectionConstraint.ts, 144, 1))
invoke: {
>invoke : Symbol(invoke, Decl(reverseMappedTypeIntersectionConstraint.ts, 166, 32))
src: "whatever",
>src : Symbol(src, Decl(reverseMappedTypeIntersectionConstraint.ts, 167, 11))
},
extra: 10
>extra : Symbol(extra, Decl(reverseMappedTypeIntersectionConstraint.ts, 169, 4))
});

View File

@ -0,0 +1,461 @@
//// [tests/cases/compiler/reverseMappedTypeIntersectionConstraint.ts] ////
=== reverseMappedTypeIntersectionConstraint.ts ===
type StateConfig<TAction extends string> = {
>StateConfig : StateConfig<TAction>
entry?: TAction
>entry : TAction | undefined
states?: Record<string, StateConfig<TAction>>;
>states : Record<string, StateConfig<TAction>> | undefined
};
type StateSchema = {
>StateSchema : { states?: Record<string, StateSchema> | undefined; }
states?: Record<string, StateSchema>;
>states : Record<string, StateSchema> | undefined
};
declare function createMachine<
>createMachine : <TConfig extends StateConfig<TAction>, TAction extends string = TConfig["entry"] extends string ? TConfig["entry"] : string>(config: { [K in keyof TConfig & keyof StateConfig<any>]: TConfig[K]; }) => [TAction, TConfig]
TConfig extends StateConfig<TAction>,
TAction extends string = TConfig["entry"] extends string ? TConfig["entry"] : string,
>(config: { [K in keyof TConfig & keyof StateConfig<any>]: TConfig[K] }): [TAction, TConfig];
>config : { [K in keyof TConfig & keyof StateConfig<any>]: TConfig[K]; }
const inferredParams1 = createMachine({
>inferredParams1 : ["foo", StateConfig<"foo">]
>createMachine({ entry: "foo", states: { a: { entry: "bar", }, }, extra: 12,}) : ["foo", StateConfig<"foo">]
>createMachine : <TConfig extends StateConfig<TAction>, TAction extends string = TConfig["entry"] extends string ? TConfig["entry"] : string>(config: { [K in keyof TConfig & keyof StateConfig<any>]: TConfig[K]; }) => [TAction, TConfig]
>{ entry: "foo", states: { a: { entry: "bar", }, }, extra: 12,} : { entry: "foo"; states: { a: { entry: "bar"; }; }; extra: number; }
entry: "foo",
>entry : "foo"
>"foo" : "foo"
states: {
>states : { a: { entry: "bar"; }; }
>{ a: { entry: "bar", }, } : { a: { entry: "bar"; }; }
a: {
>a : { entry: "bar"; }
>{ entry: "bar", } : { entry: "bar"; }
entry: "bar",
>entry : "bar"
>"bar" : "bar"
},
},
extra: 12,
>extra : number
>12 : 12
});
const inferredParams2 = createMachine({
>inferredParams2 : ["foo", { entry: "foo"; states: { a: { entry: "foo"; }; }; }]
>createMachine({ entry: "foo", states: { a: { entry: "foo", }, }, extra: 12,}) : ["foo", { entry: "foo"; states: { a: { entry: "foo"; }; }; }]
>createMachine : <TConfig extends StateConfig<TAction>, TAction extends string = TConfig["entry"] extends string ? TConfig["entry"] : string>(config: { [K in keyof TConfig & keyof StateConfig<any>]: TConfig[K]; }) => [TAction, TConfig]
>{ entry: "foo", states: { a: { entry: "foo", }, }, extra: 12,} : { entry: "foo"; states: { a: { entry: "foo"; }; }; extra: number; }
entry: "foo",
>entry : "foo"
>"foo" : "foo"
states: {
>states : { a: { entry: "foo"; }; }
>{ a: { entry: "foo", }, } : { a: { entry: "foo"; }; }
a: {
>a : { entry: "foo"; }
>{ entry: "foo", } : { entry: "foo"; }
entry: "foo",
>entry : "foo"
>"foo" : "foo"
},
},
extra: 12,
>extra : number
>12 : 12
});
// -----------------------------------------------------------------------------------------
const checkType = <T>() => <U extends T>(value: { [K in keyof U & keyof T]: U[K] }) => value;
>checkType : <T>() => <U extends T>(value: { [K in keyof U & keyof T]: U[K]; }) => { [K in keyof U & keyof T]: U[K]; }
><T>() => <U extends T>(value: { [K in keyof U & keyof T]: U[K] }) => value : <T>() => <U extends T>(value: { [K in keyof U & keyof T]: U[K]; }) => { [K in keyof U & keyof T]: U[K]; }
><U extends T>(value: { [K in keyof U & keyof T]: U[K] }) => value : <U extends T>(value: { [K in keyof U & keyof T]: U[K]; }) => { [K in keyof U & keyof T]: U[K]; }
>value : { [K in keyof U & keyof T]: U[K]; }
>value : { [K in keyof U & keyof T]: U[K]; }
const checked = checkType<{x: number, y: string}>()({
>checked : { x: number; y: "y"; }
>checkType<{x: number, y: string}>()({ x: 1 as number, y: "y", z: "z", // undesirable property z is *not* allowed}) : { x: number; y: "y"; }
>checkType<{x: number, y: string}>() : <U extends { x: number; y: string; }>(value: { [K in keyof U & ("x" | "y")]: U[K]; }) => { [K in keyof U & ("x" | "y")]: U[K]; }
>checkType : <T>() => <U extends T>(value: { [K in keyof U & keyof T]: U[K]; }) => { [K in keyof U & keyof T]: U[K]; }
>x : number
>y : string
>{ x: 1 as number, y: "y", z: "z", // undesirable property z is *not* allowed} : { x: number; y: "y"; z: string; }
x: 1 as number,
>x : number
>1 as number : number
>1 : 1
y: "y",
>y : "y"
>"y" : "y"
z: "z", // undesirable property z is *not* allowed
>z : string
>"z" : "z"
});
checked;
>checked : { x: number; y: "y"; }
// -----------------------------------------------------------------------------------------
interface Stuff {
field: number;
>field : number
anotherField: string;
>anotherField : string
}
function doStuffWithStuff<T extends Stuff>(s: { [K in keyof T & keyof Stuff]: T[K] } ): T {
>doStuffWithStuff : <T extends Stuff>(s: { [K in keyof T & keyof Stuff]: T[K]; }) => T
>s : { [K in keyof T & keyof Stuff]: T[K]; }
if(Math.random() > 0.5) {
>Math.random() > 0.5 : boolean
>Math.random() : number
>Math.random : () => number
>Math : Math
>random : () => number
>0.5 : 0.5
return s as T
>s as T : T
>s : { [K in keyof T & keyof Stuff]: T[K]; }
} else {
return s
>s : { [K in keyof T & keyof Stuff]: T[K]; }
}
}
doStuffWithStuff({ field: 1, anotherField: 'a', extra: 123 })
>doStuffWithStuff({ field: 1, anotherField: 'a', extra: 123 }) : { field: 1; anotherField: "a"; }
>doStuffWithStuff : <T extends Stuff>(s: { [K in keyof T & keyof Stuff]: T[K]; }) => T
>{ field: 1, anotherField: 'a', extra: 123 } : { field: 1; anotherField: "a"; extra: number; }
>field : 1
>1 : 1
>anotherField : "a"
>'a' : "a"
>extra : number
>123 : 123
function doStuffWithStuffArr<T extends Stuff>(arr: { [K in keyof T & keyof Stuff]: T[K] }[]): T[] {
>doStuffWithStuffArr : <T extends Stuff>(arr: { [K in keyof T & keyof Stuff]: T[K]; }[]) => T[]
>arr : { [K in keyof T & keyof Stuff]: T[K]; }[]
if(Math.random() > 0.5) {
>Math.random() > 0.5 : boolean
>Math.random() : number
>Math.random : () => number
>Math : Math
>random : () => number
>0.5 : 0.5
return arr as T[]
>arr as T[] : T[]
>arr : { [K in keyof T & keyof Stuff]: T[K]; }[]
} else {
return arr
>arr : { [K in keyof T & keyof Stuff]: T[K]; }[]
}
}
doStuffWithStuffArr([
>doStuffWithStuffArr([ { field: 1, anotherField: 'a', extra: 123 },]) : { field: 1; anotherField: "a"; }[]
>doStuffWithStuffArr : <T extends Stuff>(arr: { [K in keyof T & keyof Stuff]: T[K]; }[]) => T[]
>[ { field: 1, anotherField: 'a', extra: 123 },] : { field: 1; anotherField: "a"; extra: number; }[]
{ field: 1, anotherField: 'a', extra: 123 },
>{ field: 1, anotherField: 'a', extra: 123 } : { field: 1; anotherField: "a"; extra: number; }
>field : 1
>1 : 1
>anotherField : "a"
>'a' : "a"
>extra : number
>123 : 123
])
// -----------------------------------------------------------------------------------------
type XNumber = { x: number }
>XNumber : { x: number; }
>x : number
declare function foo<T extends XNumber>(props: {[K in keyof T & keyof XNumber]: T[K]}): void;
>foo : <T extends XNumber>(props: { [K in keyof T & "x"]: T[K]; }) => void
>props : { [K in keyof T & "x"]: T[K]; }
function bar(props: {x: number, y: string}) {
>bar : (props: { x: number; y: string;}) => void
>props : { x: number; y: string; }
>x : number
>y : string
return foo(props); // no error because lack of excess property check by design
>foo(props) : void
>foo : <T extends XNumber>(props: { [K in keyof T & "x"]: T[K]; }) => void
>props : { x: number; y: string; }
}
foo({x: 1, y: 'foo'});
>foo({x: 1, y: 'foo'}) : void
>foo : <T extends XNumber>(props: { [K in keyof T & "x"]: T[K]; }) => void
>{x: 1, y: 'foo'} : { x: 1; y: string; }
>x : 1
>1 : 1
>y : string
>'foo' : "foo"
foo({...{x: 1, y: 'foo'}}); // no error because lack of excess property check by design
>foo({...{x: 1, y: 'foo'}}) : void
>foo : <T extends XNumber>(props: { [K in keyof T & "x"]: T[K]; }) => void
>{...{x: 1, y: 'foo'}} : { x: 1; y: string; }
>{x: 1, y: 'foo'} : { x: 1; y: string; }
>x : 1
>1 : 1
>y : string
>'foo' : "foo"
// -----------------------------------------------------------------------------------------
type NoErrWithOptProps = { x: number, y?: string }
>NoErrWithOptProps : { x: number; y?: string | undefined; }
>x : number
>y : string | undefined
declare function baz<T extends NoErrWithOptProps>(props: {[K in keyof T & keyof NoErrWithOptProps]: T[K]}): void;
>baz : <T extends NoErrWithOptProps>(props: { [K in keyof T & keyof NoErrWithOptProps]: T[K]; }) => void
>props : { [K in keyof T & keyof NoErrWithOptProps]: T[K]; }
baz({x: 1});
>baz({x: 1}) : void
>baz : <T extends NoErrWithOptProps>(props: { [K in keyof T & keyof NoErrWithOptProps]: T[K]; }) => void
>{x: 1} : { x: 1; }
>x : 1
>1 : 1
baz({x: 1, z: 123});
>baz({x: 1, z: 123}) : void
>baz : <T extends NoErrWithOptProps>(props: { [K in keyof T & keyof NoErrWithOptProps]: T[K]; }) => void
>{x: 1, z: 123} : { x: 1; z: number; }
>x : 1
>1 : 1
>z : number
>123 : 123
baz({x: 1, y: 'foo'});
>baz({x: 1, y: 'foo'}) : void
>baz : <T extends NoErrWithOptProps>(props: { [K in keyof T & keyof NoErrWithOptProps]: T[K]; }) => void
>{x: 1, y: 'foo'} : { x: 1; y: "foo"; }
>x : 1
>1 : 1
>y : "foo"
>'foo' : "foo"
baz({x: 1, y: 'foo', z: 123});
>baz({x: 1, y: 'foo', z: 123}) : void
>baz : <T extends NoErrWithOptProps>(props: { [K in keyof T & keyof NoErrWithOptProps]: T[K]; }) => void
>{x: 1, y: 'foo', z: 123} : { x: 1; y: "foo"; z: number; }
>x : 1
>1 : 1
>y : "foo"
>'foo' : "foo"
>z : number
>123 : 123
// -----------------------------------------------------------------------------------------
interface WithNestedProp {
prop: string;
>prop : string
nested: {
>nested : { prop: string; }
prop: string;
>prop : string
}
}
declare function withNestedProp<T extends WithNestedProp>(props: {[K in keyof T & keyof WithNestedProp]: T[K]}): T;
>withNestedProp : <T extends WithNestedProp>(props: { [K in keyof T & keyof WithNestedProp]: T[K]; }) => T
>props : { [K in keyof T & keyof WithNestedProp]: T[K]; }
const wnp = withNestedProp({prop: 'foo', nested: { prop: 'bar' }, extra: 10 });
>wnp : { prop: "foo"; nested: { prop: string; }; }
>withNestedProp({prop: 'foo', nested: { prop: 'bar' }, extra: 10 }) : { prop: "foo"; nested: { prop: string; }; }
>withNestedProp : <T extends WithNestedProp>(props: { [K in keyof T & keyof WithNestedProp]: T[K]; }) => T
>{prop: 'foo', nested: { prop: 'bar' }, extra: 10 } : { prop: "foo"; nested: { prop: string; }; extra: number; }
>prop : "foo"
>'foo' : "foo"
>nested : { prop: string; }
>{ prop: 'bar' } : { prop: string; }
>prop : string
>'bar' : "bar"
>extra : number
>10 : 10
// -----------------------------------------------------------------------------------------
type IsLiteralString<T extends string> = string extends T ? false : true;
>IsLiteralString : IsLiteralString<T>
>false : false
>true : true
type DeepWritable<T> = T extends Function ? T : { -readonly [K in keyof T]: DeepWritable<T[K]> }
>DeepWritable : DeepWritable<T>
interface ProvidedActor {
src: string;
>src : string
logic: () => Promise<unknown>;
>logic : () => Promise<unknown>
}
type DistributeActors<TActor> = TActor extends { src: infer TSrc }
>DistributeActors : DistributeActors<TActor>
>src : TSrc
? {
src: TSrc;
>src : TSrc
}
: never;
interface MachineConfig<TActor extends ProvidedActor> {
types?: {
>types : { actors?: TActor | undefined; } | undefined
actors?: TActor;
>actors : TActor | undefined
};
invoke: IsLiteralString<TActor["src"]> extends true
>invoke : IsLiteralString<TActor["src"]> extends true ? DistributeActors<TActor> : { src: string; }
>true : true
? DistributeActors<TActor>
: {
src: string;
>src : string
};
}
type NoExtra<T> = {
>NoExtra : NoExtra<T>
[K in keyof T]: K extends keyof MachineConfig<any> ? T[K] : never
}
declare function createXMachine<
>createXMachine : <const TConfig extends MachineConfig<TActor>, TActor extends ProvidedActor = TConfig extends { types: { actors: ProvidedActor;}; } ? TConfig["types"]["actors"] : ProvidedActor>(config: { [K in keyof MachineConfig<any> & keyof TConfig]: TConfig[K]; }) => TConfig
const TConfig extends MachineConfig<TActor>,
TActor extends ProvidedActor = TConfig extends { types: { actors: ProvidedActor} } ? TConfig["types"]["actors"] : ProvidedActor,
>types : { actors: ProvidedActor; }
>actors : ProvidedActor
>(config: {[K in keyof MachineConfig<any> & keyof TConfig]: TConfig[K] }): TConfig;
>config : { [K in keyof MachineConfig<any> & keyof TConfig]: TConfig[K]; }
const child = () => Promise.resolve("foo");
>child : () => any
>() => Promise.resolve("foo") : () => any
>Promise.resolve("foo") : any
>Promise.resolve : any
>Promise : any
>resolve : any
>"foo" : "foo"
const config = createXMachine({
>config : { types: { actors: { src: "str"; logic: typeof child;}; }; invoke: { readonly src: "str"; }; }
>createXMachine({ types: {} as { actors: { src: "str"; logic: typeof child; }; }, invoke: { src: "str", }, extra: 10}) : { types: { actors: { src: "str"; logic: typeof child;}; }; invoke: { readonly src: "str"; }; }
>createXMachine : <const TConfig extends MachineConfig<TActor>, TActor extends ProvidedActor = TConfig extends { types: { actors: ProvidedActor; }; } ? TConfig["types"]["actors"] : ProvidedActor>(config: { [K in keyof MachineConfig<any> & keyof TConfig]: TConfig[K]; }) => TConfig
>{ types: {} as { actors: { src: "str"; logic: typeof child; }; }, invoke: { src: "str", }, extra: 10} : { types: { actors: { src: "str"; logic: typeof child;}; }; invoke: { src: "str"; }; extra: number; }
types: {} as {
>types : { actors: { src: "str"; logic: typeof child;}; }
>{} as { actors: { src: "str"; logic: typeof child; }; } : { actors: { src: "str"; logic: typeof child;}; }
>{} : {}
actors: {
>actors : { src: "str"; logic: typeof child; }
src: "str";
>src : "str"
logic: typeof child;
>logic : () => any
>child : () => any
};
},
invoke: {
>invoke : { src: "str"; }
>{ src: "str", } : { src: "str"; }
src: "str",
>src : "str"
>"str" : "str"
},
extra: 10
>extra : number
>10 : 10
});
const config2 = createXMachine({
>config2 : { invoke: { readonly src: "whatever"; }; }
>createXMachine({ invoke: { src: "whatever", }, extra: 10}) : { invoke: { readonly src: "whatever"; }; }
>createXMachine : <const TConfig extends MachineConfig<TActor>, TActor extends ProvidedActor = TConfig extends { types: { actors: ProvidedActor; }; } ? TConfig["types"]["actors"] : ProvidedActor>(config: { [K in keyof MachineConfig<any> & keyof TConfig]: TConfig[K]; }) => TConfig
>{ invoke: { src: "whatever", }, extra: 10} : { invoke: { src: "whatever"; }; extra: number; }
invoke: {
>invoke : { src: "whatever"; }
>{ src: "whatever", } : { src: "whatever"; }
src: "whatever",
>src : "whatever"
>"whatever" : "whatever"
},
extra: 10
>extra : number
>10 : 10
});

View File

@ -0,0 +1,24 @@
reverseMappedTypeLimitedConstraint.ts(5,13): error TS2353: Object literal may only specify known properties, and 'y' does not exist in type '{ x: 1; }'.
reverseMappedTypeLimitedConstraint.ts(14,3): error TS2353: Object literal may only specify known properties, and 'z' does not exist in type '{ x: number; y: "y"; }'.
==== reverseMappedTypeLimitedConstraint.ts (2 errors) ====
type XNumber_ = { x: number }
declare function foo_<T extends XNumber_>(props: {[K in keyof T & keyof XNumber_]: T[K]}): T;
foo_({x: 1, y: 'foo'});
~
!!! error TS2353: Object literal may only specify known properties, and 'y' does not exist in type '{ x: 1; }'.
// -----------------------------------------------------------------------------------------
const checkType_ = <T>() => <U extends T>(value: { [K in keyof U & keyof T]: U[K] }) => value;
const checked_ = checkType_<{x: number, y: string}>()({
x: 1 as number,
y: "y",
z: "z",
~
!!! error TS2353: Object literal may only specify known properties, and 'z' does not exist in type '{ x: number; y: "y"; }'.
});

View File

@ -0,0 +1,28 @@
//// [tests/cases/compiler/reverseMappedTypeLimitedConstraint.ts] ////
//// [reverseMappedTypeLimitedConstraint.ts]
type XNumber_ = { x: number }
declare function foo_<T extends XNumber_>(props: {[K in keyof T & keyof XNumber_]: T[K]}): T;
foo_({x: 1, y: 'foo'});
// -----------------------------------------------------------------------------------------
const checkType_ = <T>() => <U extends T>(value: { [K in keyof U & keyof T]: U[K] }) => value;
const checked_ = checkType_<{x: number, y: string}>()({
x: 1 as number,
y: "y",
z: "z",
});
//// [reverseMappedTypeLimitedConstraint.js]
foo_({ x: 1, y: 'foo' });
// -----------------------------------------------------------------------------------------
var checkType_ = function () { return function (value) { return value; }; };
var checked_ = checkType_()({
x: 1,
y: "y",
z: "z",
});

View File

@ -0,0 +1,55 @@
//// [tests/cases/compiler/reverseMappedTypeLimitedConstraint.ts] ////
=== reverseMappedTypeLimitedConstraint.ts ===
type XNumber_ = { x: number }
>XNumber_ : Symbol(XNumber_, Decl(reverseMappedTypeLimitedConstraint.ts, 0, 0))
>x : Symbol(x, Decl(reverseMappedTypeLimitedConstraint.ts, 0, 17))
declare function foo_<T extends XNumber_>(props: {[K in keyof T & keyof XNumber_]: T[K]}): T;
>foo_ : Symbol(foo_, Decl(reverseMappedTypeLimitedConstraint.ts, 0, 29))
>T : Symbol(T, Decl(reverseMappedTypeLimitedConstraint.ts, 2, 22))
>XNumber_ : Symbol(XNumber_, Decl(reverseMappedTypeLimitedConstraint.ts, 0, 0))
>props : Symbol(props, Decl(reverseMappedTypeLimitedConstraint.ts, 2, 42))
>K : Symbol(K, Decl(reverseMappedTypeLimitedConstraint.ts, 2, 51))
>T : Symbol(T, Decl(reverseMappedTypeLimitedConstraint.ts, 2, 22))
>XNumber_ : Symbol(XNumber_, Decl(reverseMappedTypeLimitedConstraint.ts, 0, 0))
>T : Symbol(T, Decl(reverseMappedTypeLimitedConstraint.ts, 2, 22))
>K : Symbol(K, Decl(reverseMappedTypeLimitedConstraint.ts, 2, 51))
>T : Symbol(T, Decl(reverseMappedTypeLimitedConstraint.ts, 2, 22))
foo_({x: 1, y: 'foo'});
>foo_ : Symbol(foo_, Decl(reverseMappedTypeLimitedConstraint.ts, 0, 29))
>x : Symbol(x, Decl(reverseMappedTypeLimitedConstraint.ts, 4, 6))
>y : Symbol(y, Decl(reverseMappedTypeLimitedConstraint.ts, 4, 11))
// -----------------------------------------------------------------------------------------
const checkType_ = <T>() => <U extends T>(value: { [K in keyof U & keyof T]: U[K] }) => value;
>checkType_ : Symbol(checkType_, Decl(reverseMappedTypeLimitedConstraint.ts, 8, 5))
>T : Symbol(T, Decl(reverseMappedTypeLimitedConstraint.ts, 8, 20))
>U : Symbol(U, Decl(reverseMappedTypeLimitedConstraint.ts, 8, 29))
>T : Symbol(T, Decl(reverseMappedTypeLimitedConstraint.ts, 8, 20))
>value : Symbol(value, Decl(reverseMappedTypeLimitedConstraint.ts, 8, 42))
>K : Symbol(K, Decl(reverseMappedTypeLimitedConstraint.ts, 8, 52))
>U : Symbol(U, Decl(reverseMappedTypeLimitedConstraint.ts, 8, 29))
>T : Symbol(T, Decl(reverseMappedTypeLimitedConstraint.ts, 8, 20))
>U : Symbol(U, Decl(reverseMappedTypeLimitedConstraint.ts, 8, 29))
>K : Symbol(K, Decl(reverseMappedTypeLimitedConstraint.ts, 8, 52))
>value : Symbol(value, Decl(reverseMappedTypeLimitedConstraint.ts, 8, 42))
const checked_ = checkType_<{x: number, y: string}>()({
>checked_ : Symbol(checked_, Decl(reverseMappedTypeLimitedConstraint.ts, 10, 5))
>checkType_ : Symbol(checkType_, Decl(reverseMappedTypeLimitedConstraint.ts, 8, 5))
>x : Symbol(x, Decl(reverseMappedTypeLimitedConstraint.ts, 10, 29))
>y : Symbol(y, Decl(reverseMappedTypeLimitedConstraint.ts, 10, 39))
x: 1 as number,
>x : Symbol(x, Decl(reverseMappedTypeLimitedConstraint.ts, 10, 55))
y: "y",
>y : Symbol(y, Decl(reverseMappedTypeLimitedConstraint.ts, 11, 17))
z: "z",
>z : Symbol(z, Decl(reverseMappedTypeLimitedConstraint.ts, 12, 9))
});

View File

@ -0,0 +1,52 @@
//// [tests/cases/compiler/reverseMappedTypeLimitedConstraint.ts] ////
=== reverseMappedTypeLimitedConstraint.ts ===
type XNumber_ = { x: number }
>XNumber_ : { x: number; }
>x : number
declare function foo_<T extends XNumber_>(props: {[K in keyof T & keyof XNumber_]: T[K]}): T;
>foo_ : <T extends XNumber_>(props: { [K in keyof T & "x"]: T[K]; }) => T
>props : { [K in keyof T & "x"]: T[K]; }
foo_({x: 1, y: 'foo'});
>foo_({x: 1, y: 'foo'}) : { x: 1; }
>foo_ : <T extends XNumber_>(props: { [K in keyof T & "x"]: T[K]; }) => T
>{x: 1, y: 'foo'} : { x: 1; y: string; }
>x : 1
>1 : 1
>y : string
>'foo' : "foo"
// -----------------------------------------------------------------------------------------
const checkType_ = <T>() => <U extends T>(value: { [K in keyof U & keyof T]: U[K] }) => value;
>checkType_ : <T>() => <U extends T>(value: { [K in keyof U & keyof T]: U[K]; }) => { [K in keyof U & keyof T]: U[K]; }
><T>() => <U extends T>(value: { [K in keyof U & keyof T]: U[K] }) => value : <T>() => <U extends T>(value: { [K in keyof U & keyof T]: U[K]; }) => { [K in keyof U & keyof T]: U[K]; }
><U extends T>(value: { [K in keyof U & keyof T]: U[K] }) => value : <U extends T>(value: { [K in keyof U & keyof T]: U[K]; }) => { [K in keyof U & keyof T]: U[K]; }
>value : { [K in keyof U & keyof T]: U[K]; }
>value : { [K in keyof U & keyof T]: U[K]; }
const checked_ = checkType_<{x: number, y: string}>()({
>checked_ : { x: number; y: "y"; }
>checkType_<{x: number, y: string}>()({ x: 1 as number, y: "y", z: "z",}) : { x: number; y: "y"; }
>checkType_<{x: number, y: string}>() : <U extends { x: number; y: string; }>(value: { [K in keyof U & ("x" | "y")]: U[K]; }) => { [K in keyof U & ("x" | "y")]: U[K]; }
>checkType_ : <T>() => <U extends T>(value: { [K in keyof U & keyof T]: U[K]; }) => { [K in keyof U & keyof T]: U[K]; }
>x : number
>y : string
>{ x: 1 as number, y: "y", z: "z",} : { x: number; y: "y"; z: string; }
x: 1 as number,
>x : number
>1 as number : number
>1 : 1
y: "y",
>y : "y"
>"y" : "y"
z: "z",
>z : string
>"z" : "z"
});

View File

@ -0,0 +1,174 @@
// @strict: true
type StateConfig<TAction extends string> = {
entry?: TAction
states?: Record<string, StateConfig<TAction>>;
};
type StateSchema = {
states?: Record<string, StateSchema>;
};
declare function createMachine<
TConfig extends StateConfig<TAction>,
TAction extends string = TConfig["entry"] extends string ? TConfig["entry"] : string,
>(config: { [K in keyof TConfig & keyof StateConfig<any>]: TConfig[K] }): [TAction, TConfig];
const inferredParams1 = createMachine({
entry: "foo",
states: {
a: {
entry: "bar",
},
},
extra: 12,
});
const inferredParams2 = createMachine({
entry: "foo",
states: {
a: {
entry: "foo",
},
},
extra: 12,
});
// -----------------------------------------------------------------------------------------
const checkType = <T>() => <U extends T>(value: { [K in keyof U & keyof T]: U[K] }) => value;
const checked = checkType<{x: number, y: string}>()({
x: 1 as number,
y: "y",
z: "z", // undesirable property z is *not* allowed
});
checked;
// -----------------------------------------------------------------------------------------
interface Stuff {
field: number;
anotherField: string;
}
function doStuffWithStuff<T extends Stuff>(s: { [K in keyof T & keyof Stuff]: T[K] } ): T {
if(Math.random() > 0.5) {
return s as T
} else {
return s
}
}
doStuffWithStuff({ field: 1, anotherField: 'a', extra: 123 })
function doStuffWithStuffArr<T extends Stuff>(arr: { [K in keyof T & keyof Stuff]: T[K] }[]): T[] {
if(Math.random() > 0.5) {
return arr as T[]
} else {
return arr
}
}
doStuffWithStuffArr([
{ field: 1, anotherField: 'a', extra: 123 },
])
// -----------------------------------------------------------------------------------------
type XNumber = { x: number }
declare function foo<T extends XNumber>(props: {[K in keyof T & keyof XNumber]: T[K]}): void;
function bar(props: {x: number, y: string}) {
return foo(props); // no error because lack of excess property check by design
}
foo({x: 1, y: 'foo'});
foo({...{x: 1, y: 'foo'}}); // no error because lack of excess property check by design
// -----------------------------------------------------------------------------------------
type NoErrWithOptProps = { x: number, y?: string }
declare function baz<T extends NoErrWithOptProps>(props: {[K in keyof T & keyof NoErrWithOptProps]: T[K]}): void;
baz({x: 1});
baz({x: 1, z: 123});
baz({x: 1, y: 'foo'});
baz({x: 1, y: 'foo', z: 123});
// -----------------------------------------------------------------------------------------
interface WithNestedProp {
prop: string;
nested: {
prop: string;
}
}
declare function withNestedProp<T extends WithNestedProp>(props: {[K in keyof T & keyof WithNestedProp]: T[K]}): T;
const wnp = withNestedProp({prop: 'foo', nested: { prop: 'bar' }, extra: 10 });
// -----------------------------------------------------------------------------------------
type IsLiteralString<T extends string> = string extends T ? false : true;
type DeepWritable<T> = T extends Function ? T : { -readonly [K in keyof T]: DeepWritable<T[K]> }
interface ProvidedActor {
src: string;
logic: () => Promise<unknown>;
}
type DistributeActors<TActor> = TActor extends { src: infer TSrc }
? {
src: TSrc;
}
: never;
interface MachineConfig<TActor extends ProvidedActor> {
types?: {
actors?: TActor;
};
invoke: IsLiteralString<TActor["src"]> extends true
? DistributeActors<TActor>
: {
src: string;
};
}
type NoExtra<T> = {
[K in keyof T]: K extends keyof MachineConfig<any> ? T[K] : never
}
declare function createXMachine<
const TConfig extends MachineConfig<TActor>,
TActor extends ProvidedActor = TConfig extends { types: { actors: ProvidedActor} } ? TConfig["types"]["actors"] : ProvidedActor,
>(config: {[K in keyof MachineConfig<any> & keyof TConfig]: TConfig[K] }): TConfig;
const child = () => Promise.resolve("foo");
const config = createXMachine({
types: {} as {
actors: {
src: "str";
logic: typeof child;
};
},
invoke: {
src: "str",
},
extra: 10
});
const config2 = createXMachine({
invoke: {
src: "whatever",
},
extra: 10
});

View File

@ -0,0 +1,15 @@
type XNumber_ = { x: number }
declare function foo_<T extends XNumber_>(props: {[K in keyof T & keyof XNumber_]: T[K]}): T;
foo_({x: 1, y: 'foo'});
// -----------------------------------------------------------------------------------------
const checkType_ = <T>() => <U extends T>(value: { [K in keyof U & keyof T]: U[K] }) => value;
const checked_ = checkType_<{x: number, y: string}>()({
x: 1 as number,
y: "y",
z: "z",
});