mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-04 21:53:42 -06:00
Allow type comparison when target is generic mapped type with key remapping (#45700)
* Add case for type related to for generic mapped type with as clause target * Clean up code and add baselines * cleanup
This commit is contained in:
parent
617251f2e0
commit
4f5bbd00e6
@ -18625,39 +18625,60 @@ namespace ts {
|
||||
originalErrorInfo = undefined;
|
||||
}
|
||||
}
|
||||
else if (isGenericMappedType(target) && !target.declaration.nameType) {
|
||||
// A source type T is related to a target type { [P in X]: T[P] }
|
||||
const template = getTemplateTypeFromMappedType(target);
|
||||
else if (isGenericMappedType(target)) {
|
||||
// Check if source type `S` is related to target type `{ [P in Q]: T }` or `{ [P in Q as R]: T}`.
|
||||
const keysRemapped = !!target.declaration.nameType;
|
||||
const templateType = getTemplateTypeFromMappedType(target);
|
||||
const modifiers = getMappedTypeModifiers(target);
|
||||
if (!(modifiers & MappedTypeModifiers.ExcludeOptional)) {
|
||||
if (template.flags & TypeFlags.IndexedAccess && (template as IndexedAccessType).objectType === source &&
|
||||
(template as IndexedAccessType).indexType === getTypeParameterFromMappedType(target)) {
|
||||
// If the mapped type has shape `{ [P in Q]: T[P] }`,
|
||||
// source `S` is related to target if `T` = `S`, i.e. `S` is related to `{ [P in Q]: S[P] }`.
|
||||
if (!keysRemapped && templateType.flags & TypeFlags.IndexedAccess && (templateType as IndexedAccessType).objectType === source &&
|
||||
(templateType as IndexedAccessType).indexType === getTypeParameterFromMappedType(target)) {
|
||||
return Ternary.True;
|
||||
}
|
||||
if (!isGenericMappedType(source)) {
|
||||
const targetConstraint = getConstraintTypeFromMappedType(target);
|
||||
// If target has shape `{ [P in Q as R]: T}`, then its keys have type `R`.
|
||||
// If target has shape `{ [P in Q]: T }`, then its keys have type `Q`.
|
||||
const targetKeys = keysRemapped ? getNameTypeFromMappedType(target)! : getConstraintTypeFromMappedType(target);
|
||||
// Type of the keys of source type `S`, i.e. `keyof S`.
|
||||
const sourceKeys = getIndexType(source, /*stringsOnly*/ undefined, /*noIndexSignatures*/ true);
|
||||
const includeOptional = modifiers & MappedTypeModifiers.IncludeOptional;
|
||||
const filteredByApplicability = includeOptional ? intersectTypes(targetConstraint, sourceKeys) : undefined;
|
||||
// A source type T is related to a target type { [P in Q]: X } if Q is related to keyof T and T[Q] is related to X.
|
||||
// A source type T is related to a target type { [P in Q]?: X } if some constituent Q' of Q is related to keyof T and T[Q'] is related to X.
|
||||
const filteredByApplicability = includeOptional ? intersectTypes(targetKeys, sourceKeys) : undefined;
|
||||
// A source type `S` is related to a target type `{ [P in Q]: T }` if `Q` is related to `keyof S` and `S[Q]` is related to `T`.
|
||||
// A source type `S` is related to a target type `{ [P in Q as R]: T }` if `R` is related to `keyof S` and `S[R]` is related to `T.
|
||||
// A source type `S` is related to a target type `{ [P in Q]?: T }` if some constituent `Q'` of `Q` is related to `keyof S` and `S[Q']` is related to `T`.
|
||||
// A source type `S` is related to a target type `{ [P in Q as R]?: T }` if some constituent `R'` of `R` is related to `keyof S` and `S[R']` is related to `T`.
|
||||
if (includeOptional
|
||||
? !(filteredByApplicability!.flags & TypeFlags.Never)
|
||||
: isRelatedTo(targetConstraint, sourceKeys)) {
|
||||
const templateType = getTemplateTypeFromMappedType(target);
|
||||
: isRelatedTo(targetKeys, sourceKeys)) {
|
||||
const typeParameter = getTypeParameterFromMappedType(target);
|
||||
|
||||
// Fastpath: When the template has the form Obj[P] where P is the mapped type parameter, directly compare `source` with `Obj`
|
||||
// to avoid creating the (potentially very large) number of new intermediate types made by manufacturing `source[P]`
|
||||
// Fastpath: When the template type has the form `Obj[P]` where `P` is the mapped type parameter, directly compare source `S` with `Obj`
|
||||
// to avoid creating the (potentially very large) number of new intermediate types made by manufacturing `S[P]`.
|
||||
const nonNullComponent = extractTypesOfKind(templateType, ~TypeFlags.Nullable);
|
||||
if (nonNullComponent.flags & TypeFlags.IndexedAccess && (nonNullComponent as IndexedAccessType).indexType === typeParameter) {
|
||||
if (!keysRemapped && nonNullComponent.flags & TypeFlags.IndexedAccess && (nonNullComponent as IndexedAccessType).indexType === typeParameter) {
|
||||
if (result = isRelatedTo(source, (nonNullComponent as IndexedAccessType).objectType, reportErrors)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else {
|
||||
const indexingType = filteredByApplicability ? getIntersectionType([filteredByApplicability, typeParameter]) : typeParameter;
|
||||
// We need to compare the type of a property on the source type `S` to the type of the same property on the target type,
|
||||
// so we need to construct an indexing type representing a property, and then use indexing type to index the source type for comparison.
|
||||
|
||||
// If the target type has shape `{ [P in Q]: T }`, then a property of the target has type `P`.
|
||||
// If the target type has shape `{ [P in Q]?: T }`, then a property of the target has type `P`,
|
||||
// but the property is optional, so we only want to compare properties `P` that are common between `keyof S` and `Q`.
|
||||
// If the target type has shape `{ [P in Q as R]: T }`, then a property of the target has type `R`.
|
||||
// If the target type has shape `{ [P in Q as R]?: T }`, then a property of the target has type `R`,
|
||||
// but the property is optional, so we only want to compare properties `R` that are common between `keyof S` and `R`.
|
||||
const indexingType = keysRemapped
|
||||
? (filteredByApplicability || targetKeys)
|
||||
: filteredByApplicability
|
||||
? getIntersectionType([filteredByApplicability, typeParameter])
|
||||
: typeParameter;
|
||||
const indexedAccessType = getIndexedAccessType(source, indexingType);
|
||||
// Compare `S[indexingType]` to `T`, where `T` is the type of a property of the target type.
|
||||
if (result = isRelatedTo(indexedAccessType, templateType, reportErrors)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -0,0 +1,40 @@
|
||||
tests/cases/conformance/types/mapped/mappedTypeAsClauseRelationships.ts(12,9): error TS2322: Type 'T' is not assignable to type 'Modify<T>'.
|
||||
tests/cases/conformance/types/mapped/mappedTypeAsClauseRelationships.ts(23,9): error TS2322: Type 'T' is not assignable to type 'FilterExclOpt<T>'.
|
||||
tests/cases/conformance/types/mapped/mappedTypeAsClauseRelationships.ts(24,9): error TS2322: Type 'T' is not assignable to type 'ModifyExclOpt<T>'.
|
||||
|
||||
|
||||
==== tests/cases/conformance/types/mapped/mappedTypeAsClauseRelationships.ts (3 errors) ====
|
||||
// From original issue #45212:
|
||||
type Methods<T> = { [P in keyof T as T[P] extends Function ? P : never]: T[P] };
|
||||
type H<T> = T[keyof Methods<T>]; // Ok
|
||||
|
||||
// `Filter<T>` only filters out some keys of `T`.
|
||||
type Filter<T> = { [P in keyof T as T[P] extends Function ? P : never]: T[P] };
|
||||
// `Modify<T>` might modify some keys of `T`.
|
||||
type Modify<T> = { [P in keyof T as P extends string? `bool${P}`: P]: T[P] };
|
||||
|
||||
function fun<T>(val: T) {
|
||||
let x: Filter<T> = val; // Ok
|
||||
let y: Modify<T> = val; // Error
|
||||
~
|
||||
!!! error TS2322: Type 'T' is not assignable to type 'Modify<T>'.
|
||||
}
|
||||
|
||||
type FilterInclOpt<T> = { [P in keyof T as T[P] extends Function ? P : never]+?: T[P] };
|
||||
type ModifyInclOpt<T> = { [P in keyof T as P extends string? `bool${P}`: never ]+?: T[P] };
|
||||
type FilterExclOpt<T> = { [P in keyof T as T[P] extends Function ? P : never]-?: T[P] };
|
||||
type ModifyExclOpt<T> = { [P in keyof T as P extends string? `bool${P}`: never ]-?: T[P] };
|
||||
|
||||
function fun2<T>(val: T) {
|
||||
let x: FilterInclOpt<T> = val; // Ok
|
||||
let y: ModifyInclOpt<T> = val; // Ok
|
||||
let z: FilterExclOpt<T> = val; // Error
|
||||
~
|
||||
!!! error TS2322: Type 'T' is not assignable to type 'FilterExclOpt<T>'.
|
||||
let w: ModifyExclOpt<T> = val; // Error
|
||||
~
|
||||
!!! error TS2322: Type 'T' is not assignable to type 'ModifyExclOpt<T>'.
|
||||
}
|
||||
|
||||
|
||||
|
||||
41
tests/baselines/reference/mappedTypeAsClauseRelationships.js
Normal file
41
tests/baselines/reference/mappedTypeAsClauseRelationships.js
Normal file
@ -0,0 +1,41 @@
|
||||
//// [mappedTypeAsClauseRelationships.ts]
|
||||
// From original issue #45212:
|
||||
type Methods<T> = { [P in keyof T as T[P] extends Function ? P : never]: T[P] };
|
||||
type H<T> = T[keyof Methods<T>]; // Ok
|
||||
|
||||
// `Filter<T>` only filters out some keys of `T`.
|
||||
type Filter<T> = { [P in keyof T as T[P] extends Function ? P : never]: T[P] };
|
||||
// `Modify<T>` might modify some keys of `T`.
|
||||
type Modify<T> = { [P in keyof T as P extends string? `bool${P}`: P]: T[P] };
|
||||
|
||||
function fun<T>(val: T) {
|
||||
let x: Filter<T> = val; // Ok
|
||||
let y: Modify<T> = val; // Error
|
||||
}
|
||||
|
||||
type FilterInclOpt<T> = { [P in keyof T as T[P] extends Function ? P : never]+?: T[P] };
|
||||
type ModifyInclOpt<T> = { [P in keyof T as P extends string? `bool${P}`: never ]+?: T[P] };
|
||||
type FilterExclOpt<T> = { [P in keyof T as T[P] extends Function ? P : never]-?: T[P] };
|
||||
type ModifyExclOpt<T> = { [P in keyof T as P extends string? `bool${P}`: never ]-?: T[P] };
|
||||
|
||||
function fun2<T>(val: T) {
|
||||
let x: FilterInclOpt<T> = val; // Ok
|
||||
let y: ModifyInclOpt<T> = val; // Ok
|
||||
let z: FilterExclOpt<T> = val; // Error
|
||||
let w: ModifyExclOpt<T> = val; // Error
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//// [mappedTypeAsClauseRelationships.js]
|
||||
function fun(val) {
|
||||
var x = val; // Ok
|
||||
var y = val; // Error
|
||||
}
|
||||
function fun2(val) {
|
||||
var x = val; // Ok
|
||||
var y = val; // Ok
|
||||
var z = val; // Error
|
||||
var w = val; // Error
|
||||
}
|
||||
@ -0,0 +1,142 @@
|
||||
=== tests/cases/conformance/types/mapped/mappedTypeAsClauseRelationships.ts ===
|
||||
// From original issue #45212:
|
||||
type Methods<T> = { [P in keyof T as T[P] extends Function ? P : never]: T[P] };
|
||||
>Methods : Symbol(Methods, Decl(mappedTypeAsClauseRelationships.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 1, 13))
|
||||
>P : Symbol(P, Decl(mappedTypeAsClauseRelationships.ts, 1, 21))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 1, 13))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 1, 13))
|
||||
>P : Symbol(P, Decl(mappedTypeAsClauseRelationships.ts, 1, 21))
|
||||
>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>P : Symbol(P, Decl(mappedTypeAsClauseRelationships.ts, 1, 21))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 1, 13))
|
||||
>P : Symbol(P, Decl(mappedTypeAsClauseRelationships.ts, 1, 21))
|
||||
|
||||
type H<T> = T[keyof Methods<T>]; // Ok
|
||||
>H : Symbol(H, Decl(mappedTypeAsClauseRelationships.ts, 1, 80))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 2, 7))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 2, 7))
|
||||
>Methods : Symbol(Methods, Decl(mappedTypeAsClauseRelationships.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 2, 7))
|
||||
|
||||
// `Filter<T>` only filters out some keys of `T`.
|
||||
type Filter<T> = { [P in keyof T as T[P] extends Function ? P : never]: T[P] };
|
||||
>Filter : Symbol(Filter, Decl(mappedTypeAsClauseRelationships.ts, 2, 32))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 5, 12))
|
||||
>P : Symbol(P, Decl(mappedTypeAsClauseRelationships.ts, 5, 20))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 5, 12))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 5, 12))
|
||||
>P : Symbol(P, Decl(mappedTypeAsClauseRelationships.ts, 5, 20))
|
||||
>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>P : Symbol(P, Decl(mappedTypeAsClauseRelationships.ts, 5, 20))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 5, 12))
|
||||
>P : Symbol(P, Decl(mappedTypeAsClauseRelationships.ts, 5, 20))
|
||||
|
||||
// `Modify<T>` might modify some keys of `T`.
|
||||
type Modify<T> = { [P in keyof T as P extends string? `bool${P}`: P]: T[P] };
|
||||
>Modify : Symbol(Modify, Decl(mappedTypeAsClauseRelationships.ts, 5, 79))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 7, 12))
|
||||
>P : Symbol(P, Decl(mappedTypeAsClauseRelationships.ts, 7, 20))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 7, 12))
|
||||
>P : Symbol(P, Decl(mappedTypeAsClauseRelationships.ts, 7, 20))
|
||||
>P : Symbol(P, Decl(mappedTypeAsClauseRelationships.ts, 7, 20))
|
||||
>P : Symbol(P, Decl(mappedTypeAsClauseRelationships.ts, 7, 20))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 7, 12))
|
||||
>P : Symbol(P, Decl(mappedTypeAsClauseRelationships.ts, 7, 20))
|
||||
|
||||
function fun<T>(val: T) {
|
||||
>fun : Symbol(fun, Decl(mappedTypeAsClauseRelationships.ts, 7, 77))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 9, 13))
|
||||
>val : Symbol(val, Decl(mappedTypeAsClauseRelationships.ts, 9, 16))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 9, 13))
|
||||
|
||||
let x: Filter<T> = val; // Ok
|
||||
>x : Symbol(x, Decl(mappedTypeAsClauseRelationships.ts, 10, 7))
|
||||
>Filter : Symbol(Filter, Decl(mappedTypeAsClauseRelationships.ts, 2, 32))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 9, 13))
|
||||
>val : Symbol(val, Decl(mappedTypeAsClauseRelationships.ts, 9, 16))
|
||||
|
||||
let y: Modify<T> = val; // Error
|
||||
>y : Symbol(y, Decl(mappedTypeAsClauseRelationships.ts, 11, 7))
|
||||
>Modify : Symbol(Modify, Decl(mappedTypeAsClauseRelationships.ts, 5, 79))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 9, 13))
|
||||
>val : Symbol(val, Decl(mappedTypeAsClauseRelationships.ts, 9, 16))
|
||||
}
|
||||
|
||||
type FilterInclOpt<T> = { [P in keyof T as T[P] extends Function ? P : never]+?: T[P] };
|
||||
>FilterInclOpt : Symbol(FilterInclOpt, Decl(mappedTypeAsClauseRelationships.ts, 12, 1))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 14, 19))
|
||||
>P : Symbol(P, Decl(mappedTypeAsClauseRelationships.ts, 14, 27))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 14, 19))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 14, 19))
|
||||
>P : Symbol(P, Decl(mappedTypeAsClauseRelationships.ts, 14, 27))
|
||||
>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>P : Symbol(P, Decl(mappedTypeAsClauseRelationships.ts, 14, 27))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 14, 19))
|
||||
>P : Symbol(P, Decl(mappedTypeAsClauseRelationships.ts, 14, 27))
|
||||
|
||||
type ModifyInclOpt<T> = { [P in keyof T as P extends string? `bool${P}`: never ]+?: T[P] };
|
||||
>ModifyInclOpt : Symbol(ModifyInclOpt, Decl(mappedTypeAsClauseRelationships.ts, 14, 88))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 15, 19))
|
||||
>P : Symbol(P, Decl(mappedTypeAsClauseRelationships.ts, 15, 27))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 15, 19))
|
||||
>P : Symbol(P, Decl(mappedTypeAsClauseRelationships.ts, 15, 27))
|
||||
>P : Symbol(P, Decl(mappedTypeAsClauseRelationships.ts, 15, 27))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 15, 19))
|
||||
>P : Symbol(P, Decl(mappedTypeAsClauseRelationships.ts, 15, 27))
|
||||
|
||||
type FilterExclOpt<T> = { [P in keyof T as T[P] extends Function ? P : never]-?: T[P] };
|
||||
>FilterExclOpt : Symbol(FilterExclOpt, Decl(mappedTypeAsClauseRelationships.ts, 15, 91))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 16, 19))
|
||||
>P : Symbol(P, Decl(mappedTypeAsClauseRelationships.ts, 16, 27))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 16, 19))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 16, 19))
|
||||
>P : Symbol(P, Decl(mappedTypeAsClauseRelationships.ts, 16, 27))
|
||||
>Function : Symbol(Function, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
|
||||
>P : Symbol(P, Decl(mappedTypeAsClauseRelationships.ts, 16, 27))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 16, 19))
|
||||
>P : Symbol(P, Decl(mappedTypeAsClauseRelationships.ts, 16, 27))
|
||||
|
||||
type ModifyExclOpt<T> = { [P in keyof T as P extends string? `bool${P}`: never ]-?: T[P] };
|
||||
>ModifyExclOpt : Symbol(ModifyExclOpt, Decl(mappedTypeAsClauseRelationships.ts, 16, 88))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 17, 19))
|
||||
>P : Symbol(P, Decl(mappedTypeAsClauseRelationships.ts, 17, 27))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 17, 19))
|
||||
>P : Symbol(P, Decl(mappedTypeAsClauseRelationships.ts, 17, 27))
|
||||
>P : Symbol(P, Decl(mappedTypeAsClauseRelationships.ts, 17, 27))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 17, 19))
|
||||
>P : Symbol(P, Decl(mappedTypeAsClauseRelationships.ts, 17, 27))
|
||||
|
||||
function fun2<T>(val: T) {
|
||||
>fun2 : Symbol(fun2, Decl(mappedTypeAsClauseRelationships.ts, 17, 91))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 19, 14))
|
||||
>val : Symbol(val, Decl(mappedTypeAsClauseRelationships.ts, 19, 17))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 19, 14))
|
||||
|
||||
let x: FilterInclOpt<T> = val; // Ok
|
||||
>x : Symbol(x, Decl(mappedTypeAsClauseRelationships.ts, 20, 7))
|
||||
>FilterInclOpt : Symbol(FilterInclOpt, Decl(mappedTypeAsClauseRelationships.ts, 12, 1))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 19, 14))
|
||||
>val : Symbol(val, Decl(mappedTypeAsClauseRelationships.ts, 19, 17))
|
||||
|
||||
let y: ModifyInclOpt<T> = val; // Ok
|
||||
>y : Symbol(y, Decl(mappedTypeAsClauseRelationships.ts, 21, 7))
|
||||
>ModifyInclOpt : Symbol(ModifyInclOpt, Decl(mappedTypeAsClauseRelationships.ts, 14, 88))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 19, 14))
|
||||
>val : Symbol(val, Decl(mappedTypeAsClauseRelationships.ts, 19, 17))
|
||||
|
||||
let z: FilterExclOpt<T> = val; // Error
|
||||
>z : Symbol(z, Decl(mappedTypeAsClauseRelationships.ts, 22, 7))
|
||||
>FilterExclOpt : Symbol(FilterExclOpt, Decl(mappedTypeAsClauseRelationships.ts, 15, 91))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 19, 14))
|
||||
>val : Symbol(val, Decl(mappedTypeAsClauseRelationships.ts, 19, 17))
|
||||
|
||||
let w: ModifyExclOpt<T> = val; // Error
|
||||
>w : Symbol(w, Decl(mappedTypeAsClauseRelationships.ts, 23, 7))
|
||||
>ModifyExclOpt : Symbol(ModifyExclOpt, Decl(mappedTypeAsClauseRelationships.ts, 16, 88))
|
||||
>T : Symbol(T, Decl(mappedTypeAsClauseRelationships.ts, 19, 14))
|
||||
>val : Symbol(val, Decl(mappedTypeAsClauseRelationships.ts, 19, 17))
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,64 @@
|
||||
=== tests/cases/conformance/types/mapped/mappedTypeAsClauseRelationships.ts ===
|
||||
// From original issue #45212:
|
||||
type Methods<T> = { [P in keyof T as T[P] extends Function ? P : never]: T[P] };
|
||||
>Methods : Methods<T>
|
||||
|
||||
type H<T> = T[keyof Methods<T>]; // Ok
|
||||
>H : H<T>
|
||||
|
||||
// `Filter<T>` only filters out some keys of `T`.
|
||||
type Filter<T> = { [P in keyof T as T[P] extends Function ? P : never]: T[P] };
|
||||
>Filter : Filter<T>
|
||||
|
||||
// `Modify<T>` might modify some keys of `T`.
|
||||
type Modify<T> = { [P in keyof T as P extends string? `bool${P}`: P]: T[P] };
|
||||
>Modify : Modify<T>
|
||||
|
||||
function fun<T>(val: T) {
|
||||
>fun : <T>(val: T) => void
|
||||
>val : T
|
||||
|
||||
let x: Filter<T> = val; // Ok
|
||||
>x : Filter<T>
|
||||
>val : T
|
||||
|
||||
let y: Modify<T> = val; // Error
|
||||
>y : Modify<T>
|
||||
>val : T
|
||||
}
|
||||
|
||||
type FilterInclOpt<T> = { [P in keyof T as T[P] extends Function ? P : never]+?: T[P] };
|
||||
>FilterInclOpt : FilterInclOpt<T>
|
||||
|
||||
type ModifyInclOpt<T> = { [P in keyof T as P extends string? `bool${P}`: never ]+?: T[P] };
|
||||
>ModifyInclOpt : ModifyInclOpt<T>
|
||||
|
||||
type FilterExclOpt<T> = { [P in keyof T as T[P] extends Function ? P : never]-?: T[P] };
|
||||
>FilterExclOpt : FilterExclOpt<T>
|
||||
|
||||
type ModifyExclOpt<T> = { [P in keyof T as P extends string? `bool${P}`: never ]-?: T[P] };
|
||||
>ModifyExclOpt : ModifyExclOpt<T>
|
||||
|
||||
function fun2<T>(val: T) {
|
||||
>fun2 : <T>(val: T) => void
|
||||
>val : T
|
||||
|
||||
let x: FilterInclOpt<T> = val; // Ok
|
||||
>x : FilterInclOpt<T>
|
||||
>val : T
|
||||
|
||||
let y: ModifyInclOpt<T> = val; // Ok
|
||||
>y : ModifyInclOpt<T>
|
||||
>val : T
|
||||
|
||||
let z: FilterExclOpt<T> = val; // Error
|
||||
>z : FilterExclOpt<T>
|
||||
>val : T
|
||||
|
||||
let w: ModifyExclOpt<T> = val; // Error
|
||||
>w : ModifyExclOpt<T>
|
||||
>val : T
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
// From original issue #45212:
|
||||
type Methods<T> = { [P in keyof T as T[P] extends Function ? P : never]: T[P] };
|
||||
type H<T> = T[keyof Methods<T>]; // Ok
|
||||
|
||||
// `Filter<T>` only filters out some keys of `T`.
|
||||
type Filter<T> = { [P in keyof T as T[P] extends Function ? P : never]: T[P] };
|
||||
// `Modify<T>` might modify some keys of `T`.
|
||||
type Modify<T> = { [P in keyof T as P extends string? `bool${P}`: P]: T[P] };
|
||||
|
||||
function fun<T>(val: T) {
|
||||
let x: Filter<T> = val; // Ok
|
||||
let y: Modify<T> = val; // Error
|
||||
}
|
||||
|
||||
type FilterInclOpt<T> = { [P in keyof T as T[P] extends Function ? P : never]+?: T[P] };
|
||||
type ModifyInclOpt<T> = { [P in keyof T as P extends string? `bool${P}`: never ]+?: T[P] };
|
||||
type FilterExclOpt<T> = { [P in keyof T as T[P] extends Function ? P : never]-?: T[P] };
|
||||
type ModifyExclOpt<T> = { [P in keyof T as P extends string? `bool${P}`: never ]-?: T[P] };
|
||||
|
||||
function fun2<T>(val: T) {
|
||||
let x: FilterInclOpt<T> = val; // Ok
|
||||
let y: ModifyInclOpt<T> = val; // Ok
|
||||
let z: FilterExclOpt<T> = val; // Error
|
||||
let w: ModifyExclOpt<T> = val; // Error
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user