mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-10-28 16:36:04 +08:00
Strengthen and unify negated type <-> filtering conditional workaround rule
This commit is contained in:
11 files changed
+1689
-32
No files matched your search
@@ -152,6 +152,11 @@ type CachedTypeKey struct {
|
||||
typeId TypeId
|
||||
}
|
||||
|
||||
type DistributiveInstantiationKey struct {
|
||||
typeId TypeId
|
||||
typeParameterId TypeId
|
||||
}
|
||||
|
||||
// NarrowedTypeKey
|
||||
|
||||
type NarrowedTypeKey struct {
|
||||
@@ -651,6 +656,7 @@ type Checker struct {
|
||||
thisExpandoLocations map[*ast.Symbol]*ast.Node
|
||||
subtypeReductionCache map[CacheHashKey][]*Type
|
||||
cachedTypes map[CachedTypeKey]*Type
|
||||
distributiveInstantiationCache map[DistributiveInstantiationKey]bool
|
||||
cachedSignatures map[CachedSignatureKey]*Signature
|
||||
undefinedProperties map[*ast.Symbol]*ast.Symbol
|
||||
narrowedTypes map[NarrowedTypeKey]*Type
|
||||
@@ -990,6 +996,7 @@ func NewChecker(program Program, tracer *Tracer) (*Checker, *sync.Mutex) {
|
||||
c.thisExpandoLocations = make(map[*ast.Symbol]*ast.Node)
|
||||
c.subtypeReductionCache = make(map[CacheHashKey][]*Type)
|
||||
c.cachedTypes = make(map[CachedTypeKey]*Type)
|
||||
c.distributiveInstantiationCache = make(map[DistributiveInstantiationKey]bool)
|
||||
c.cachedSignatures = make(map[CachedSignatureKey]*Signature)
|
||||
c.undefinedProperties = make(map[*ast.Symbol]*ast.Symbol)
|
||||
c.narrowedTypes = make(map[NarrowedTypeKey]*Type)
|
||||
|
||||
@@ -3616,8 +3616,8 @@ func (r *Relater) structuredTypeRelatedToWorker(source *Type, target *Type, repo
|
||||
nameType := r.c.getNameTypeFromMappedType(targetType)
|
||||
constraintType := r.c.getConstraintTypeFromMappedType(targetType)
|
||||
var targetKeys *Type
|
||||
isFiltering := nameType != nil && r.c.isMappedTypeWithKeyofConstraintDeclaration(targetType)
|
||||
if isFiltering {
|
||||
isRemappedKeyof := nameType != nil && r.c.isMappedTypeWithKeyofConstraintDeclaration(targetType)
|
||||
if isRemappedKeyof {
|
||||
// we need to get the apparent mappings and union them with the generic mappings, since some properties may be
|
||||
// missing from the `constraintType` which will otherwise be mapped in the object
|
||||
mappedKeys := r.c.getApparentMappedTypeKeys(nameType, targetType)
|
||||
@@ -3628,15 +3628,14 @@ func (r *Relater) structuredTypeRelatedToWorker(source *Type, target *Type, repo
|
||||
} else {
|
||||
targetKeys = constraintType
|
||||
}
|
||||
if isFiltering && source.flags&TypeFlagsIntersection != 0 && r.someTypeRelatedToType(source, constraintType, false, intersectionState) == TernaryTrue {
|
||||
// run the filter over `source` - some part of `source` is related to the constraint - if source's other elements end up filtering the same way the nameType does, the assignment can pass
|
||||
// This effectively is a workaround for a lack of distributive conditional/distributive homomorphic mapped types relationship rules that uses execution of the distribution (even at higher order)
|
||||
// to approximate a better result.
|
||||
// See the homomorphic case in tsc\testdata\tests\cases\compiler\indexMappedTypeWithFilteredKeysWithNegation.ts
|
||||
sourceInstantiatedTarget := r.c.instantiateType(nameType, newSimpleTypeMapper(r.c.getTypeParameterFromMappedType(targetType), source))
|
||||
broadTargetKeys := r.c.getUnionType([]*Type{targetKeys, sourceInstantiatedTarget})
|
||||
if r.isRelatedTo(source, broadTargetKeys, RecursionFlagsTarget, false) == TernaryTrue {
|
||||
return TernaryTrue
|
||||
if isRemappedKeyof && source.flags&TypeFlagsIntersection != 0 {
|
||||
if filteredNameType := r.getOptionalSimplificationOfConditional(nameType); filteredNameType != nil && r.someTypeRelatedToType(source, constraintType, false, intersectionState) == TernaryTrue {
|
||||
// Apply the filter only to a source already constrained to the mapped keys.
|
||||
sourceInstantiatedTarget := r.c.instantiateType(filteredNameType, newSimpleTypeMapper(r.c.getTypeParameterFromMappedType(targetType), source))
|
||||
broadTargetKeys := r.c.getUnionType([]*Type{targetKeys, sourceInstantiatedTarget})
|
||||
if r.isRelatedTo(source, broadTargetKeys, RecursionFlagsTarget, false) == TernaryTrue {
|
||||
return TernaryTrue
|
||||
}
|
||||
}
|
||||
}
|
||||
if r.isRelatedTo(source, targetKeys, RecursionFlagsTarget, reportErrors) == TernaryTrue {
|
||||
@@ -4024,32 +4023,72 @@ func (r *Relater) structuredTypeRelatedToWorker(source *Type, target *Type, repo
|
||||
return TernaryFalse
|
||||
}
|
||||
|
||||
// TODO: Replace this heuristic with proper distributive conditional type relationship rules.
|
||||
// For a distributive A extends B ? never : Q<A> without infer parameters, rewrite to Q<A & not B>.
|
||||
// A definitely false check uses Q<A> unchanged; a definitely true check cannot use the rewrite.
|
||||
// Otherwise B must be independent of A, and Q<never> must be never. The conditional already distributes,
|
||||
// but we also probe whether Q<X | Y> agrees with Q<X> | Q<Y> before moving the union inside Q.
|
||||
// See Repeated in indexMappedTypeWithFilteredKeysWithNegationErrors.ts, where moving the union
|
||||
// inside `${A}-${A}` would lose the correlation between occurrences of A.
|
||||
func (r *Relater) getOptionalSimplificationOfConditional(target *Type) *Type {
|
||||
if target.flags&TypeFlagsConditional == 0 {
|
||||
return nil
|
||||
}
|
||||
// TODO: This is a kludge for not having proper rules for relating distributive conditional types.
|
||||
// We rewrite `A extends B ? never : Q<A>` into `Q<A & not B>` - provided that substitution
|
||||
// actually changes it. This is not *particularly* accurate, but enables the common case of relating a filtering mapped type to the equivalent filtering negated type.
|
||||
// See the non-homomorphic case in tsc\testdata\tests\cases\compiler\indexMappedTypeWithFilteredKeysWithNegation.ts for an example.
|
||||
root := target.AsConditionalType().root
|
||||
if root.isDistributive && r.c.getTrueTypeFromConditionalType(target).flags&TypeFlagsNever != 0 {
|
||||
f := r.c.getFalseTypeFromConditionalType(target)
|
||||
remappedFalseType := r.c.instantiateType(
|
||||
r.c.getTypeFromTypeNode(root.node.FalseType),
|
||||
r.c.combineTypeMappers(
|
||||
newSimpleTypeMapper(
|
||||
getNonDistributedTypeParameter(root.checkType),
|
||||
r.c.getIntersectionType([]*Type{root.checkType, r.c.getNegatedType(root.extendsType)}),
|
||||
),
|
||||
target.AsConditionalType().mapper,
|
||||
),
|
||||
)
|
||||
if remappedFalseType != f {
|
||||
return remappedFalseType
|
||||
}
|
||||
conditional := target.AsConditionalType()
|
||||
root := conditional.root
|
||||
if !root.isDistributive || len(root.inferTypeParameters) != 0 || r.c.getTrueTypeFromConditionalType(target).flags&TypeFlagsNever == 0 {
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
permissiveExtendsType := r.c.getPermissiveInstantiation(conditional.extendsType)
|
||||
skipTrue := !someType(r.c.getPermissiveInstantiation(conditional.checkType), func(t *Type) bool {
|
||||
return r.c.isTypeAssignableTo(t, permissiveExtendsType)
|
||||
})
|
||||
if skipTrue {
|
||||
return r.c.getFalseTypeFromConditionalType(target)
|
||||
}
|
||||
if r.c.isTypeAssignableTo(r.c.getRestrictiveInstantiation(conditional.checkType), r.c.getRestrictiveInstantiation(conditional.extendsType)) {
|
||||
return nil
|
||||
}
|
||||
checkType := getNonDistributedTypeParameter(root.checkType)
|
||||
if r.c.isTypeParameterPossiblyReferenced(checkType, root.node.ExtendsType) {
|
||||
return nil
|
||||
}
|
||||
falseType := r.c.getTypeFromTypeNode(root.node.FalseType)
|
||||
if !r.canDistributeTypeInstantiation(falseType, checkType) {
|
||||
return nil
|
||||
}
|
||||
return r.c.instantiateType(
|
||||
falseType,
|
||||
r.c.combineTypeMappers(
|
||||
newSimpleTypeMapper(checkType, r.c.getIntersectionType([]*Type{root.checkType, r.c.getNegatedType(root.extendsType)})),
|
||||
conditional.mapper,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
func (r *Relater) canDistributeTypeInstantiation(t *Type, typeParameter *Type) bool {
|
||||
key := DistributiveInstantiationKey{typeId: t.id, typeParameterId: typeParameter.id}
|
||||
if result, ok := r.c.distributiveInstantiationCache[key]; ok {
|
||||
return result
|
||||
}
|
||||
// A recursive probe is unproven until the outer comparison completes.
|
||||
r.c.distributiveInstantiationCache[key] = false
|
||||
// Filtering can remove the entire check type, so the false branch must also preserve never.
|
||||
if r.c.instantiateType(t, newSimpleTypeMapper(typeParameter, r.c.neverType)).flags&TypeFlagsNever == 0 {
|
||||
return false
|
||||
}
|
||||
left := r.c.markerSuperType
|
||||
right := r.c.markerOtherType
|
||||
instantiate := func(argument *Type) *Type {
|
||||
return r.c.getSimplifiedType(r.c.instantiateType(t, newSimpleTypeMapper(typeParameter, argument)), false /*writing*/)
|
||||
}
|
||||
// Require execution over unrelated union members to agree with distributing first.
|
||||
// Use the existing identity comparison rather than introducing conditional relationship rules.
|
||||
instantiatedUnion := instantiate(r.c.getUnionType([]*Type{left, right}))
|
||||
unionOfInstantiations := r.c.getUnionType([]*Type{instantiate(left), instantiate(right)})
|
||||
result := r.c.isTypeIdenticalTo(instantiatedUnion, unionOfInstantiations)
|
||||
r.c.distributiveInstantiationCache[key] = result
|
||||
return result
|
||||
}
|
||||
|
||||
func (r *Relater) typeArgumentsRelatedTo(sources []*Type, targets []*Type, variances []VarianceFlags, reportErrors bool, intersectionState IntersectionState) Ternary {
|
||||
|
||||
+138
@@ -39,6 +39,102 @@ const t1: T1 = ['b', 'c'];
|
||||
|
||||
type S1<T> = { [K in keyof T & string as K extends '_key' ? never : K]: 1 }[LocalExclude<keyof T & string, '_key'>];
|
||||
type S2<T> = { [K in string & keyof T as K extends '_key' ? never : K]: 1 }[LocalExclude<string & keyof T, '_key'>];
|
||||
|
||||
type ConditionalExclude<T, U> = T extends U ? never : T;
|
||||
|
||||
function exclude<T, U>(value: T & not U): ConditionalExclude<T, U> {
|
||||
return value;
|
||||
}
|
||||
|
||||
type Identity<T> = T;
|
||||
type AliasedExclude<T, U> = T extends U ? never : Identity<T>;
|
||||
|
||||
function aliasedExclude<T, U>(value: T & not U): AliasedExclude<T, U> {
|
||||
return value;
|
||||
}
|
||||
|
||||
function mappedExclude<T, U>(value: keyof T & not U): keyof ExcludeKey<T, U> {
|
||||
return value;
|
||||
}
|
||||
|
||||
type AliasedExcludeKey<T, U> = {
|
||||
[K in keyof T as ConditionalExclude<K, U>]: T[K]
|
||||
};
|
||||
|
||||
function aliasedMappedExclude<T, U>(value: keyof T & not U): keyof AliasedExcludeKey<T, U> {
|
||||
return value;
|
||||
}
|
||||
|
||||
type Prefixed<T extends string> = T extends "skip" ? never : `prefix${T}`;
|
||||
|
||||
function prefixed<T extends string>(value: `prefix${T & not "skip"}`): Prefixed<T> {
|
||||
return value;
|
||||
}
|
||||
|
||||
type WithSuffix<T extends string, S extends string> = T extends "skip" ? never : `prefix${T}:${S}`;
|
||||
|
||||
function withSuffix<T extends string, S extends string>(value: `prefix${T & not "skip"}:${S}`): WithSuffix<T, S> {
|
||||
return value;
|
||||
}
|
||||
|
||||
type Cased<T extends string> = Uppercase<`prefix${Lowercase<T>}`>;
|
||||
type FilteredCased<T extends string> = T extends "skip" ? never : Cased<T>;
|
||||
|
||||
function cased<T extends string>(value: Cased<T & not "skip">): FilteredCased<T> {
|
||||
return value;
|
||||
}
|
||||
|
||||
type Alternatives<T extends string> = T extends "skip" ? never : `left${T}` | `right${Uppercase<T>}`;
|
||||
|
||||
function alternatives<T extends string>(
|
||||
value: `left${T & not "skip"}` | `right${Uppercase<T & not "skip">}`
|
||||
): Alternatives<T> {
|
||||
return value;
|
||||
}
|
||||
|
||||
type Branded<T> = T extends "skip" ? never : T & { brand: true };
|
||||
|
||||
function branded<T>(value: T & not "skip" & { brand: true }): Branded<T> {
|
||||
return value;
|
||||
}
|
||||
|
||||
interface Values {
|
||||
a: 1;
|
||||
b: 2;
|
||||
skip: 3;
|
||||
}
|
||||
|
||||
type Lookup<T extends keyof Values> = T extends "skip" ? never : Values[T];
|
||||
|
||||
function lookup<T extends keyof Values>(value: Values[T & not "skip"]): Lookup<T> {
|
||||
return value;
|
||||
}
|
||||
|
||||
type PrefixedKeys<T> = {
|
||||
[K in keyof T & string as K extends "_key" ? never : `prefix${K}`]: T[K]
|
||||
};
|
||||
|
||||
function prefixedKey<T>(value: `prefix${keyof T & string & not "_key"}`): keyof PrefixedKeys<T> {
|
||||
return value;
|
||||
}
|
||||
|
||||
type FunctionResult<T> = T extends string ? never : () => T;
|
||||
|
||||
function falseFunction<T>(value: () => [T]): FunctionResult<[T]> {
|
||||
return value;
|
||||
}
|
||||
|
||||
type TupleResult<T> = T extends string ? never : [T, T];
|
||||
|
||||
function falseTuple<T>(value: [[T], [T]]): TupleResult<[T]> {
|
||||
return value;
|
||||
}
|
||||
|
||||
type Nested<T extends string> = T extends "skip" ? never : ConditionalExclude<`prefix${T}`, "prefixomit">;
|
||||
|
||||
function nested<T extends string>(value: ConditionalExclude<`prefix${T & not "skip"}`, "prefixomit">): Nested<T> {
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
//// [indexMappedTypeWithFilteredKeysWithNegation.js]
|
||||
@@ -48,3 +144,45 @@ function f(test, possibleKey) {
|
||||
test[possibleKey];
|
||||
}
|
||||
const t1 = ['b', 'c'];
|
||||
function exclude(value) {
|
||||
return value;
|
||||
}
|
||||
function aliasedExclude(value) {
|
||||
return value;
|
||||
}
|
||||
function mappedExclude(value) {
|
||||
return value;
|
||||
}
|
||||
function aliasedMappedExclude(value) {
|
||||
return value;
|
||||
}
|
||||
function prefixed(value) {
|
||||
return value;
|
||||
}
|
||||
function withSuffix(value) {
|
||||
return value;
|
||||
}
|
||||
function cased(value) {
|
||||
return value;
|
||||
}
|
||||
function alternatives(value) {
|
||||
return value;
|
||||
}
|
||||
function branded(value) {
|
||||
return value;
|
||||
}
|
||||
function lookup(value) {
|
||||
return value;
|
||||
}
|
||||
function prefixedKey(value) {
|
||||
return value;
|
||||
}
|
||||
function falseFunction(value) {
|
||||
return value;
|
||||
}
|
||||
function falseTuple(value) {
|
||||
return value;
|
||||
}
|
||||
function nested(value) {
|
||||
return value;
|
||||
}
|
||||
Vendored
+331
@@ -137,3 +137,334 @@ type S2<T> = { [K in string & keyof T as K extends '_key' ? never : K]: 1 }[Loca
|
||||
>LocalExclude : Symbol(LocalExclude, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 18, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 37, 8))
|
||||
|
||||
type ConditionalExclude<T, U> = T extends U ? never : T;
|
||||
>ConditionalExclude : Symbol(ConditionalExclude, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 37, 116))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 39, 24))
|
||||
>U : Symbol(U, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 39, 26))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 39, 24))
|
||||
>U : Symbol(U, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 39, 26))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 39, 24))
|
||||
|
||||
function exclude<T, U>(value: T & not U): ConditionalExclude<T, U> {
|
||||
>exclude : Symbol(exclude, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 39, 56))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 41, 17))
|
||||
>U : Symbol(U, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 41, 19))
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 41, 23))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 41, 17))
|
||||
>U : Symbol(U, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 41, 19))
|
||||
>ConditionalExclude : Symbol(ConditionalExclude, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 37, 116))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 41, 17))
|
||||
>U : Symbol(U, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 41, 19))
|
||||
|
||||
return value;
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 41, 23))
|
||||
}
|
||||
|
||||
type Identity<T> = T;
|
||||
>Identity : Symbol(Identity, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 43, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 45, 14))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 45, 14))
|
||||
|
||||
type AliasedExclude<T, U> = T extends U ? never : Identity<T>;
|
||||
>AliasedExclude : Symbol(AliasedExclude, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 45, 21))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 46, 20))
|
||||
>U : Symbol(U, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 46, 22))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 46, 20))
|
||||
>U : Symbol(U, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 46, 22))
|
||||
>Identity : Symbol(Identity, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 43, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 46, 20))
|
||||
|
||||
function aliasedExclude<T, U>(value: T & not U): AliasedExclude<T, U> {
|
||||
>aliasedExclude : Symbol(aliasedExclude, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 46, 62))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 48, 24))
|
||||
>U : Symbol(U, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 48, 26))
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 48, 30))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 48, 24))
|
||||
>U : Symbol(U, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 48, 26))
|
||||
>AliasedExclude : Symbol(AliasedExclude, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 45, 21))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 48, 24))
|
||||
>U : Symbol(U, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 48, 26))
|
||||
|
||||
return value;
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 48, 30))
|
||||
}
|
||||
|
||||
function mappedExclude<T, U>(value: keyof T & not U): keyof ExcludeKey<T, U> {
|
||||
>mappedExclude : Symbol(mappedExclude, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 50, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 52, 23))
|
||||
>U : Symbol(U, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 52, 25))
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 52, 29))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 52, 23))
|
||||
>U : Symbol(U, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 52, 25))
|
||||
>ExcludeKey : Symbol(ExcludeKey, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 52, 23))
|
||||
>U : Symbol(U, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 52, 25))
|
||||
|
||||
return value;
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 52, 29))
|
||||
}
|
||||
|
||||
type AliasedExcludeKey<T, U> = {
|
||||
>AliasedExcludeKey : Symbol(AliasedExcludeKey, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 54, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 56, 23))
|
||||
>U : Symbol(U, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 56, 25))
|
||||
|
||||
[K in keyof T as ConditionalExclude<K, U>]: T[K]
|
||||
>K : Symbol(K, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 57, 5))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 56, 23))
|
||||
>ConditionalExclude : Symbol(ConditionalExclude, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 37, 116))
|
||||
>K : Symbol(K, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 57, 5))
|
||||
>U : Symbol(U, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 56, 25))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 56, 23))
|
||||
>K : Symbol(K, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 57, 5))
|
||||
|
||||
};
|
||||
|
||||
function aliasedMappedExclude<T, U>(value: keyof T & not U): keyof AliasedExcludeKey<T, U> {
|
||||
>aliasedMappedExclude : Symbol(aliasedMappedExclude, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 58, 2))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 60, 30))
|
||||
>U : Symbol(U, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 60, 32))
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 60, 36))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 60, 30))
|
||||
>U : Symbol(U, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 60, 32))
|
||||
>AliasedExcludeKey : Symbol(AliasedExcludeKey, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 54, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 60, 30))
|
||||
>U : Symbol(U, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 60, 32))
|
||||
|
||||
return value;
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 60, 36))
|
||||
}
|
||||
|
||||
type Prefixed<T extends string> = T extends "skip" ? never : `prefix${T}`;
|
||||
>Prefixed : Symbol(Prefixed, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 62, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 64, 14))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 64, 14))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 64, 14))
|
||||
|
||||
function prefixed<T extends string>(value: `prefix${T & not "skip"}`): Prefixed<T> {
|
||||
>prefixed : Symbol(prefixed, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 64, 74))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 66, 18))
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 66, 36))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 66, 18))
|
||||
>Prefixed : Symbol(Prefixed, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 62, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 66, 18))
|
||||
|
||||
return value;
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 66, 36))
|
||||
}
|
||||
|
||||
type WithSuffix<T extends string, S extends string> = T extends "skip" ? never : `prefix${T}:${S}`;
|
||||
>WithSuffix : Symbol(WithSuffix, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 68, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 70, 16))
|
||||
>S : Symbol(S, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 70, 33))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 70, 16))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 70, 16))
|
||||
>S : Symbol(S, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 70, 33))
|
||||
|
||||
function withSuffix<T extends string, S extends string>(value: `prefix${T & not "skip"}:${S}`): WithSuffix<T, S> {
|
||||
>withSuffix : Symbol(withSuffix, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 70, 99))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 72, 20))
|
||||
>S : Symbol(S, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 72, 37))
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 72, 56))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 72, 20))
|
||||
>S : Symbol(S, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 72, 37))
|
||||
>WithSuffix : Symbol(WithSuffix, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 68, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 72, 20))
|
||||
>S : Symbol(S, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 72, 37))
|
||||
|
||||
return value;
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 72, 56))
|
||||
}
|
||||
|
||||
type Cased<T extends string> = Uppercase<`prefix${Lowercase<T>}`>;
|
||||
>Cased : Symbol(Cased, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 74, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 76, 11))
|
||||
>Uppercase : Symbol(Uppercase, Decl(lib.es5.d.ts, --, --))
|
||||
>Lowercase : Symbol(Lowercase, Decl(lib.es5.d.ts, --, --))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 76, 11))
|
||||
|
||||
type FilteredCased<T extends string> = T extends "skip" ? never : Cased<T>;
|
||||
>FilteredCased : Symbol(FilteredCased, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 76, 66))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 77, 19))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 77, 19))
|
||||
>Cased : Symbol(Cased, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 74, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 77, 19))
|
||||
|
||||
function cased<T extends string>(value: Cased<T & not "skip">): FilteredCased<T> {
|
||||
>cased : Symbol(cased, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 77, 75))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 79, 15))
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 79, 33))
|
||||
>Cased : Symbol(Cased, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 74, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 79, 15))
|
||||
>FilteredCased : Symbol(FilteredCased, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 76, 66))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 79, 15))
|
||||
|
||||
return value;
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 79, 33))
|
||||
}
|
||||
|
||||
type Alternatives<T extends string> = T extends "skip" ? never : `left${T}` | `right${Uppercase<T>}`;
|
||||
>Alternatives : Symbol(Alternatives, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 81, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 83, 18))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 83, 18))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 83, 18))
|
||||
>Uppercase : Symbol(Uppercase, Decl(lib.es5.d.ts, --, --))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 83, 18))
|
||||
|
||||
function alternatives<T extends string>(
|
||||
>alternatives : Symbol(alternatives, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 83, 101))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 85, 22))
|
||||
|
||||
value: `left${T & not "skip"}` | `right${Uppercase<T & not "skip">}`
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 85, 40))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 85, 22))
|
||||
>Uppercase : Symbol(Uppercase, Decl(lib.es5.d.ts, --, --))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 85, 22))
|
||||
|
||||
): Alternatives<T> {
|
||||
>Alternatives : Symbol(Alternatives, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 81, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 85, 22))
|
||||
|
||||
return value;
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 85, 40))
|
||||
}
|
||||
|
||||
type Branded<T> = T extends "skip" ? never : T & { brand: true };
|
||||
>Branded : Symbol(Branded, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 89, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 91, 13))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 91, 13))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 91, 13))
|
||||
>brand : Symbol(brand, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 91, 50))
|
||||
|
||||
function branded<T>(value: T & not "skip" & { brand: true }): Branded<T> {
|
||||
>branded : Symbol(branded, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 91, 65))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 93, 17))
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 93, 20))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 93, 17))
|
||||
>brand : Symbol(brand, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 93, 45))
|
||||
>Branded : Symbol(Branded, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 89, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 93, 17))
|
||||
|
||||
return value;
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 93, 20))
|
||||
}
|
||||
|
||||
interface Values {
|
||||
>Values : Symbol(Values, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 95, 1))
|
||||
|
||||
a: 1;
|
||||
>a : Symbol(Values.a, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 97, 18))
|
||||
|
||||
b: 2;
|
||||
>b : Symbol(Values.b, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 98, 9))
|
||||
|
||||
skip: 3;
|
||||
>skip : Symbol(Values.skip, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 99, 9))
|
||||
}
|
||||
|
||||
type Lookup<T extends keyof Values> = T extends "skip" ? never : Values[T];
|
||||
>Lookup : Symbol(Lookup, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 101, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 103, 12))
|
||||
>Values : Symbol(Values, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 95, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 103, 12))
|
||||
>Values : Symbol(Values, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 95, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 103, 12))
|
||||
|
||||
function lookup<T extends keyof Values>(value: Values[T & not "skip"]): Lookup<T> {
|
||||
>lookup : Symbol(lookup, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 103, 75))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 105, 16))
|
||||
>Values : Symbol(Values, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 95, 1))
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 105, 40))
|
||||
>Values : Symbol(Values, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 95, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 105, 16))
|
||||
>Lookup : Symbol(Lookup, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 101, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 105, 16))
|
||||
|
||||
return value;
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 105, 40))
|
||||
}
|
||||
|
||||
type PrefixedKeys<T> = {
|
||||
>PrefixedKeys : Symbol(PrefixedKeys, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 107, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 109, 18))
|
||||
|
||||
[K in keyof T & string as K extends "_key" ? never : `prefix${K}`]: T[K]
|
||||
>K : Symbol(K, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 110, 5))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 109, 18))
|
||||
>K : Symbol(K, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 110, 5))
|
||||
>K : Symbol(K, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 110, 5))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 109, 18))
|
||||
>K : Symbol(K, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 110, 5))
|
||||
|
||||
};
|
||||
|
||||
function prefixedKey<T>(value: `prefix${keyof T & string & not "_key"}`): keyof PrefixedKeys<T> {
|
||||
>prefixedKey : Symbol(prefixedKey, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 111, 2))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 113, 21))
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 113, 24))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 113, 21))
|
||||
>PrefixedKeys : Symbol(PrefixedKeys, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 107, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 113, 21))
|
||||
|
||||
return value;
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 113, 24))
|
||||
}
|
||||
|
||||
type FunctionResult<T> = T extends string ? never : () => T;
|
||||
>FunctionResult : Symbol(FunctionResult, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 115, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 117, 20))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 117, 20))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 117, 20))
|
||||
|
||||
function falseFunction<T>(value: () => [T]): FunctionResult<[T]> {
|
||||
>falseFunction : Symbol(falseFunction, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 117, 60))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 119, 23))
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 119, 26))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 119, 23))
|
||||
>FunctionResult : Symbol(FunctionResult, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 115, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 119, 23))
|
||||
|
||||
return value;
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 119, 26))
|
||||
}
|
||||
|
||||
type TupleResult<T> = T extends string ? never : [T, T];
|
||||
>TupleResult : Symbol(TupleResult, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 121, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 123, 17))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 123, 17))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 123, 17))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 123, 17))
|
||||
|
||||
function falseTuple<T>(value: [[T], [T]]): TupleResult<[T]> {
|
||||
>falseTuple : Symbol(falseTuple, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 123, 56))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 125, 20))
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 125, 23))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 125, 20))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 125, 20))
|
||||
>TupleResult : Symbol(TupleResult, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 121, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 125, 20))
|
||||
|
||||
return value;
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 125, 23))
|
||||
}
|
||||
|
||||
type Nested<T extends string> = T extends "skip" ? never : ConditionalExclude<`prefix${T}`, "prefixomit">;
|
||||
>Nested : Symbol(Nested, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 127, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 129, 12))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 129, 12))
|
||||
>ConditionalExclude : Symbol(ConditionalExclude, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 37, 116))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 129, 12))
|
||||
|
||||
function nested<T extends string>(value: ConditionalExclude<`prefix${T & not "skip"}`, "prefixomit">): Nested<T> {
|
||||
>nested : Symbol(nested, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 129, 106))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 131, 16))
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 131, 34))
|
||||
>ConditionalExclude : Symbol(ConditionalExclude, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 37, 116))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 131, 16))
|
||||
>Nested : Symbol(Nested, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 127, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 131, 16))
|
||||
|
||||
return value;
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegation.ts, 131, 34))
|
||||
}
|
||||
|
||||
Vendored
+181
@@ -79,3 +79,184 @@ type S1<T> = { [K in keyof T & string as K extends '_key' ? never : K]: 1 }[Loca
|
||||
type S2<T> = { [K in string & keyof T as K extends '_key' ? never : K]: 1 }[LocalExclude<string & keyof T, '_key'>];
|
||||
>S2 : S2<T>
|
||||
|
||||
type ConditionalExclude<T, U> = T extends U ? never : T;
|
||||
>ConditionalExclude : ConditionalExclude<T, U>
|
||||
|
||||
function exclude<T, U>(value: T & not U): ConditionalExclude<T, U> {
|
||||
>exclude : <T, U>(value: T & not U) => ConditionalExclude<T, U>
|
||||
>value : T & not U
|
||||
|
||||
return value;
|
||||
>value : T & not U
|
||||
}
|
||||
|
||||
type Identity<T> = T;
|
||||
>Identity : T
|
||||
|
||||
type AliasedExclude<T, U> = T extends U ? never : Identity<T>;
|
||||
>AliasedExclude : AliasedExclude<T, U>
|
||||
|
||||
function aliasedExclude<T, U>(value: T & not U): AliasedExclude<T, U> {
|
||||
>aliasedExclude : <T, U>(value: T & not U) => AliasedExclude<T, U>
|
||||
>value : T & not U
|
||||
|
||||
return value;
|
||||
>value : T & not U
|
||||
}
|
||||
|
||||
function mappedExclude<T, U>(value: keyof T & not U): keyof ExcludeKey<T, U> {
|
||||
>mappedExclude : <T, U>(value: keyof T & not U) => keyof ExcludeKey<T, U>
|
||||
>value : keyof T & not U
|
||||
|
||||
return value;
|
||||
>value : keyof T & not U
|
||||
}
|
||||
|
||||
type AliasedExcludeKey<T, U> = {
|
||||
>AliasedExcludeKey : AliasedExcludeKey<T, U>
|
||||
|
||||
[K in keyof T as ConditionalExclude<K, U>]: T[K]
|
||||
};
|
||||
|
||||
function aliasedMappedExclude<T, U>(value: keyof T & not U): keyof AliasedExcludeKey<T, U> {
|
||||
>aliasedMappedExclude : <T, U>(value: keyof T & not U) => keyof AliasedExcludeKey<T, U>
|
||||
>value : keyof T & not U
|
||||
|
||||
return value;
|
||||
>value : keyof T & not U
|
||||
}
|
||||
|
||||
type Prefixed<T extends string> = T extends "skip" ? never : `prefix${T}`;
|
||||
>Prefixed : Prefixed<T>
|
||||
|
||||
function prefixed<T extends string>(value: `prefix${T & not "skip"}`): Prefixed<T> {
|
||||
>prefixed : <T extends string>(value: `prefix${T & not "skip"}`) => Prefixed<T>
|
||||
>value : `prefix${T & not "skip"}`
|
||||
|
||||
return value;
|
||||
>value : `prefix${T & not "skip"}`
|
||||
}
|
||||
|
||||
type WithSuffix<T extends string, S extends string> = T extends "skip" ? never : `prefix${T}:${S}`;
|
||||
>WithSuffix : WithSuffix<T, S>
|
||||
|
||||
function withSuffix<T extends string, S extends string>(value: `prefix${T & not "skip"}:${S}`): WithSuffix<T, S> {
|
||||
>withSuffix : <T extends string, S extends string>(value: `prefix${T & not "skip"}:${S}`) => WithSuffix<T, S>
|
||||
>value : `prefix${T & not "skip"}:${S}`
|
||||
|
||||
return value;
|
||||
>value : `prefix${T & not "skip"}:${S}`
|
||||
}
|
||||
|
||||
type Cased<T extends string> = Uppercase<`prefix${Lowercase<T>}`>;
|
||||
>Cased : `PREFIX${Uppercase<Lowercase<T>>}`
|
||||
|
||||
type FilteredCased<T extends string> = T extends "skip" ? never : Cased<T>;
|
||||
>FilteredCased : FilteredCased<T>
|
||||
|
||||
function cased<T extends string>(value: Cased<T & not "skip">): FilteredCased<T> {
|
||||
>cased : <T extends string>(value: Cased<T & not "skip">) => FilteredCased<T>
|
||||
>value : `PREFIX${Uppercase<Lowercase<T & not "skip">>}`
|
||||
|
||||
return value;
|
||||
>value : `PREFIX${Uppercase<Lowercase<T & not "skip">>}`
|
||||
}
|
||||
|
||||
type Alternatives<T extends string> = T extends "skip" ? never : `left${T}` | `right${Uppercase<T>}`;
|
||||
>Alternatives : Alternatives<T>
|
||||
|
||||
function alternatives<T extends string>(
|
||||
>alternatives : <T extends string>(value: `left${T & not "skip"}` | `right${Uppercase<T & not "skip">}`) => Alternatives<T>
|
||||
|
||||
value: `left${T & not "skip"}` | `right${Uppercase<T & not "skip">}`
|
||||
>value : `left${T & not "skip"}` | `right${Uppercase<T & not "skip">}`
|
||||
|
||||
): Alternatives<T> {
|
||||
return value;
|
||||
>value : `left${T & not "skip"}` | `right${Uppercase<T & not "skip">}`
|
||||
}
|
||||
|
||||
type Branded<T> = T extends "skip" ? never : T & { brand: true };
|
||||
>Branded : Branded<T>
|
||||
>brand : true
|
||||
>true : true
|
||||
|
||||
function branded<T>(value: T & not "skip" & { brand: true }): Branded<T> {
|
||||
>branded : <T>(value: T & not "skip" & { brand: true; }) => Branded<T>
|
||||
>value : T & not "skip" & { brand: true; }
|
||||
>brand : true
|
||||
>true : true
|
||||
|
||||
return value;
|
||||
>value : T & not "skip" & { brand: true; }
|
||||
}
|
||||
|
||||
interface Values {
|
||||
a: 1;
|
||||
>a : 1
|
||||
|
||||
b: 2;
|
||||
>b : 2
|
||||
|
||||
skip: 3;
|
||||
>skip : 3
|
||||
}
|
||||
|
||||
type Lookup<T extends keyof Values> = T extends "skip" ? never : Values[T];
|
||||
>Lookup : Lookup<T>
|
||||
|
||||
function lookup<T extends keyof Values>(value: Values[T & not "skip"]): Lookup<T> {
|
||||
>lookup : <T extends keyof Values>(value: Values[T & not "skip"]) => Lookup<T>
|
||||
>value : Values[T & not "skip"]
|
||||
|
||||
return value;
|
||||
>value : Values[T & not "skip"]
|
||||
}
|
||||
|
||||
type PrefixedKeys<T> = {
|
||||
>PrefixedKeys : PrefixedKeys<T>
|
||||
|
||||
[K in keyof T & string as K extends "_key" ? never : `prefix${K}`]: T[K]
|
||||
};
|
||||
|
||||
function prefixedKey<T>(value: `prefix${keyof T & string & not "_key"}`): keyof PrefixedKeys<T> {
|
||||
>prefixedKey : <T>(value: `prefix${keyof T & string & not "_key"}`) => keyof PrefixedKeys<T>
|
||||
>value : `prefix${keyof T & string & not "_key"}`
|
||||
|
||||
return value;
|
||||
>value : `prefix${keyof T & string & not "_key"}`
|
||||
}
|
||||
|
||||
type FunctionResult<T> = T extends string ? never : () => T;
|
||||
>FunctionResult : FunctionResult<T>
|
||||
|
||||
function falseFunction<T>(value: () => [T]): FunctionResult<[T]> {
|
||||
>falseFunction : <T>(value: () => [T]) => FunctionResult<[T]>
|
||||
>value : () => [T]
|
||||
|
||||
return value;
|
||||
>value : () => [T]
|
||||
}
|
||||
|
||||
type TupleResult<T> = T extends string ? never : [T, T];
|
||||
>TupleResult : TupleResult<T>
|
||||
|
||||
function falseTuple<T>(value: [[T], [T]]): TupleResult<[T]> {
|
||||
>falseTuple : <T>(value: [[T], [T]]) => TupleResult<[T]>
|
||||
>value : [[T], [T]]
|
||||
|
||||
return value;
|
||||
>value : [[T], [T]]
|
||||
}
|
||||
|
||||
type Nested<T extends string> = T extends "skip" ? never : ConditionalExclude<`prefix${T}`, "prefixomit">;
|
||||
>Nested : Nested<T>
|
||||
|
||||
function nested<T extends string>(value: ConditionalExclude<`prefix${T & not "skip"}`, "prefixomit">): Nested<T> {
|
||||
>nested : <T extends string>(value: ConditionalExclude<`prefix${T & not "skip"}`, "prefixomit">) => Nested<T>
|
||||
>value : ConditionalExclude<`prefix${T & not "skip"}`, "prefixomit">
|
||||
|
||||
return value;
|
||||
>value : ConditionalExclude<`prefix${T & not "skip"}`, "prefixomit">
|
||||
}
|
||||
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
indexMappedTypeWithFilteredKeysWithNegationErrors.ts(5,5): error TS2322: Type '() => never' is not assignable to type 'FilteredFunction<T>'.
|
||||
indexMappedTypeWithFilteredKeysWithNegationErrors.ts(14,5): error TS2322: Type '[T & not false & not true, T & not false & not true]' is not assignable to type 'FilteredPair<T>'.
|
||||
indexMappedTypeWithFilteredKeysWithNegationErrors.ts(24,5): error TS2322: Type 'T & not Omitted<T>' is not assignable to type 'DependentFilter<T>'.
|
||||
indexMappedTypeWithFilteredKeysWithNegationErrors.ts(33,5): error TS2322: Type 'T' is not assignable to type 'Filter<T, U>'.
|
||||
indexMappedTypeWithFilteredKeysWithNegationErrors.ts(42,5): error TS2322: Type 'keyof T & not "c"' is not assignable to type 'keyof FilteredKeys<T>'.
|
||||
Type 'keyof T & not "c"' is not assignable to type 'K extends "b" ? never : K'.
|
||||
indexMappedTypeWithFilteredKeysWithNegationErrors.ts(47,5): error TS2322: Type 'string & not "b"' is not assignable to type 'keyof FilteredKeys<T>'.
|
||||
Type 'string & not "b"' is not assignable to type 'K extends "b" ? never : K'.
|
||||
indexMappedTypeWithFilteredKeysWithNegationErrors.ts(58,5): error TS2322: Type 'keyof T & not "c"' is not assignable to type 'keyof RemappedKeys<T>'.
|
||||
Type 'keyof T & not "c"' is not assignable to type '"a" | "b" extends K ? K : never'.
|
||||
indexMappedTypeWithFilteredKeysWithNegationErrors.ts(67,5): error TS2322: Type 'keyof T & not Omitted<keyof T>' is not assignable to type 'keyof DependentKeys<T>'.
|
||||
Type 'keyof T & not Omitted<keyof T>' is not assignable to type 'K extends Omitted<K> ? never : K'.
|
||||
indexMappedTypeWithFilteredKeysWithNegationErrors.ts(74,5): error TS2322: Type '`${T & not "skip"}-${T & not "skip"}`' is not assignable to type 'Repeated<T>'.
|
||||
Type '`${string}-${string}`' is not assignable to type 'Repeated<T>'.
|
||||
indexMappedTypeWithFilteredKeysWithNegationErrors.ts(83,5): error TS2322: Type 'T & not string & { value: T & not string; }' is not assignable to type 'Correlated<T>'.
|
||||
indexMappedTypeWithFilteredKeysWithNegationErrors.ts(88,5): error TS2322: Type '() => string & { value: T; }' is not assignable to type 'never'.
|
||||
indexMappedTypeWithFilteredKeysWithNegationErrors.ts(93,5): error TS2322: Type '() => string | [T]' is not assignable to type '() => [T]'.
|
||||
Type 'string | [T]' is not assignable to type '[T]'.
|
||||
Type 'string' is not assignable to type '[T]'.
|
||||
|
||||
|
||||
==== indexMappedTypeWithFilteredKeysWithNegationErrors.ts (12 errors) ====
|
||||
type FilteredFunction<T> = T extends string ? never : () => T;
|
||||
|
||||
function makeFunction<T>(): FilteredFunction<T> {
|
||||
// When T is string, FilteredFunction<T> is never, but this still returns a function.
|
||||
return () => { throw new Error(); };
|
||||
~~~~~~
|
||||
!!! error TS2322: Type '() => never' is not assignable to type 'FilteredFunction<T>'.
|
||||
}
|
||||
|
||||
const impossibleFunction: never = makeFunction<string>();
|
||||
|
||||
type FilteredPair<T> = T extends boolean ? never : [T, T];
|
||||
|
||||
function makePair<T>(value: [T & not boolean, T & not boolean]): FilteredPair<T> {
|
||||
// The tuple elements can come from different union members, unlike the distributed FilteredPair<T>.
|
||||
return value;
|
||||
~~~~~~
|
||||
!!! error TS2322: Type '[T & not false & not true, T & not false & not true]' is not assignable to type 'FilteredPair<T>'.
|
||||
}
|
||||
|
||||
const homogeneousPair: [string, string] | [number, number] = makePair<string | number>(["a", 1]);
|
||||
|
||||
type Omitted<T> = "a" extends T ? never : "b";
|
||||
type DependentFilter<T> = T extends Omitted<T> ? never : T;
|
||||
|
||||
function dependentFilter<T>(value: T & not Omitted<T>): DependentFilter<T> {
|
||||
// For T = "a" | "b", Omitted<T> is never, so value can be "b", but DependentFilter<T> is "a".
|
||||
return value;
|
||||
~~~~~~
|
||||
!!! error TS2322: Type 'T & not Omitted<T>' is not assignable to type 'DependentFilter<T>'.
|
||||
}
|
||||
|
||||
const onlyA: "a" = dependentFilter<"a" | "b">("b");
|
||||
|
||||
type Filter<T, U> = T extends U ? never : T;
|
||||
|
||||
function unfiltered<T, U>(value: T): Filter<T, U> {
|
||||
// value can still belong to U, whose members are excluded from Filter<T, U>.
|
||||
return value;
|
||||
~~~~~~
|
||||
!!! error TS2322: Type 'T' is not assignable to type 'Filter<T, U>'.
|
||||
}
|
||||
|
||||
type FilteredKeys<T> = {
|
||||
[K in keyof T as K extends "b" ? never : K]: T[K]
|
||||
};
|
||||
|
||||
function excludedKey<T>(value: keyof T & not "c"): keyof FilteredKeys<T> {
|
||||
// Excluding "c" does not prevent value from being the filtered-out key "b".
|
||||
return value;
|
||||
~~~~~~
|
||||
!!! error TS2322: Type 'keyof T & not "c"' is not assignable to type 'keyof FilteredKeys<T>'.
|
||||
!!! error TS2322: Type 'keyof T & not "c"' is not assignable to type 'K extends "b" ? never : K'.
|
||||
}
|
||||
|
||||
function unrelatedKey<T>(value: string & not "b"): keyof FilteredKeys<T> {
|
||||
// value is not constrained to keyof T and may name a property T does not have.
|
||||
return value;
|
||||
~~~~~~
|
||||
!!! error TS2322: Type 'string & not "b"' is not assignable to type 'keyof FilteredKeys<T>'.
|
||||
!!! error TS2322: Type 'string & not "b"' is not assignable to type 'K extends "b" ? never : K'.
|
||||
}
|
||||
|
||||
type RemappedKeys<T> = {
|
||||
[K in keyof T as ("a" | "b") extends K ? K : never]: T[K]
|
||||
};
|
||||
|
||||
function remappedKey<T extends { a: unknown; b: unknown }>(
|
||||
value: keyof T & not "c"
|
||||
): keyof RemappedKeys<T> {
|
||||
// For T with just "a" and "b", neither key accepts their union, so no keys survive.
|
||||
return value;
|
||||
~~~~~~
|
||||
!!! error TS2322: Type 'keyof T & not "c"' is not assignable to type 'keyof RemappedKeys<T>'.
|
||||
!!! error TS2322: Type 'keyof T & not "c"' is not assignable to type '"a" | "b" extends K ? K : never'.
|
||||
}
|
||||
|
||||
type DependentKeys<T> = {
|
||||
[K in keyof T as K extends Omitted<K> ? never : K]: T[K]
|
||||
};
|
||||
|
||||
function dependentKey<T>(value: keyof T & not Omitted<keyof T>): keyof DependentKeys<T> {
|
||||
// For T = { a: number; b: number }, value can be "b", but only "a" survives the per-key filter.
|
||||
return value;
|
||||
~~~~~~
|
||||
!!! error TS2322: Type 'keyof T & not Omitted<keyof T>' is not assignable to type 'keyof DependentKeys<T>'.
|
||||
!!! error TS2322: Type 'keyof T & not Omitted<keyof T>' is not assignable to type 'K extends Omitted<K> ? never : K'.
|
||||
}
|
||||
|
||||
type Repeated<T extends string> = T extends "skip" ? never : `${T}-${T}`;
|
||||
|
||||
function repeated<T extends string>(value: `${T & not "skip"}-${T & not "skip"}`): Repeated<T> {
|
||||
// value can mix different union members in its two T positions, unlike Repeated<T>.
|
||||
return value;
|
||||
~~~~~~
|
||||
!!! error TS2322: Type '`${T & not "skip"}-${T & not "skip"}`' is not assignable to type 'Repeated<T>'.
|
||||
!!! error TS2322: Type '`${string}-${string}`' is not assignable to type 'Repeated<T>'.
|
||||
}
|
||||
|
||||
const same: "a-a" | "b-b" = repeated<"a" | "b">("a-b");
|
||||
|
||||
type Correlated<T> = T extends string ? never : T & { value: T };
|
||||
|
||||
function correlated<T>(value: T & not string & { value: T & not string }): Correlated<T> {
|
||||
// The outer T and the value property's T can come from different union members, unlike Correlated<T>.
|
||||
return value;
|
||||
~~~~~~
|
||||
!!! error TS2322: Type 'T & not string & { value: T & not string; }' is not assignable to type 'Correlated<T>'.
|
||||
}
|
||||
|
||||
function trueFunction<T>(value: () => (string & { value: T })): FilteredFunction<string & { value: T }> {
|
||||
// The check type always extends string, so the result is never, not a function.
|
||||
return value;
|
||||
~~~~~~
|
||||
!!! error TS2322: Type '() => string & { value: T; }' is not assignable to type 'never'.
|
||||
}
|
||||
|
||||
function unionFunction<T>(value: () => ([T] | string)): FilteredFunction<[T] | string> {
|
||||
// The string union member is filtered out, so the returned function must return [T], not string.
|
||||
return value;
|
||||
~~~~~~
|
||||
!!! error TS2322: Type '() => string | [T]' is not assignable to type '() => [T]'.
|
||||
!!! error TS2322: Type 'string | [T]' is not assignable to type '[T]'.
|
||||
!!! error TS2322: Type 'string' is not assignable to type '[T]'.
|
||||
}
|
||||
|
||||
Vendored
+153
@@ -0,0 +1,153 @@
|
||||
//// [tests/cases/compiler/indexMappedTypeWithFilteredKeysWithNegationErrors.ts] ////
|
||||
|
||||
//// [indexMappedTypeWithFilteredKeysWithNegationErrors.ts]
|
||||
type FilteredFunction<T> = T extends string ? never : () => T;
|
||||
|
||||
function makeFunction<T>(): FilteredFunction<T> {
|
||||
// When T is string, FilteredFunction<T> is never, but this still returns a function.
|
||||
return () => { throw new Error(); };
|
||||
}
|
||||
|
||||
const impossibleFunction: never = makeFunction<string>();
|
||||
|
||||
type FilteredPair<T> = T extends boolean ? never : [T, T];
|
||||
|
||||
function makePair<T>(value: [T & not boolean, T & not boolean]): FilteredPair<T> {
|
||||
// The tuple elements can come from different union members, unlike the distributed FilteredPair<T>.
|
||||
return value;
|
||||
}
|
||||
|
||||
const homogeneousPair: [string, string] | [number, number] = makePair<string | number>(["a", 1]);
|
||||
|
||||
type Omitted<T> = "a" extends T ? never : "b";
|
||||
type DependentFilter<T> = T extends Omitted<T> ? never : T;
|
||||
|
||||
function dependentFilter<T>(value: T & not Omitted<T>): DependentFilter<T> {
|
||||
// For T = "a" | "b", Omitted<T> is never, so value can be "b", but DependentFilter<T> is "a".
|
||||
return value;
|
||||
}
|
||||
|
||||
const onlyA: "a" = dependentFilter<"a" | "b">("b");
|
||||
|
||||
type Filter<T, U> = T extends U ? never : T;
|
||||
|
||||
function unfiltered<T, U>(value: T): Filter<T, U> {
|
||||
// value can still belong to U, whose members are excluded from Filter<T, U>.
|
||||
return value;
|
||||
}
|
||||
|
||||
type FilteredKeys<T> = {
|
||||
[K in keyof T as K extends "b" ? never : K]: T[K]
|
||||
};
|
||||
|
||||
function excludedKey<T>(value: keyof T & not "c"): keyof FilteredKeys<T> {
|
||||
// Excluding "c" does not prevent value from being the filtered-out key "b".
|
||||
return value;
|
||||
}
|
||||
|
||||
function unrelatedKey<T>(value: string & not "b"): keyof FilteredKeys<T> {
|
||||
// value is not constrained to keyof T and may name a property T does not have.
|
||||
return value;
|
||||
}
|
||||
|
||||
type RemappedKeys<T> = {
|
||||
[K in keyof T as ("a" | "b") extends K ? K : never]: T[K]
|
||||
};
|
||||
|
||||
function remappedKey<T extends { a: unknown; b: unknown }>(
|
||||
value: keyof T & not "c"
|
||||
): keyof RemappedKeys<T> {
|
||||
// For T with just "a" and "b", neither key accepts their union, so no keys survive.
|
||||
return value;
|
||||
}
|
||||
|
||||
type DependentKeys<T> = {
|
||||
[K in keyof T as K extends Omitted<K> ? never : K]: T[K]
|
||||
};
|
||||
|
||||
function dependentKey<T>(value: keyof T & not Omitted<keyof T>): keyof DependentKeys<T> {
|
||||
// For T = { a: number; b: number }, value can be "b", but only "a" survives the per-key filter.
|
||||
return value;
|
||||
}
|
||||
|
||||
type Repeated<T extends string> = T extends "skip" ? never : `${T}-${T}`;
|
||||
|
||||
function repeated<T extends string>(value: `${T & not "skip"}-${T & not "skip"}`): Repeated<T> {
|
||||
// value can mix different union members in its two T positions, unlike Repeated<T>.
|
||||
return value;
|
||||
}
|
||||
|
||||
const same: "a-a" | "b-b" = repeated<"a" | "b">("a-b");
|
||||
|
||||
type Correlated<T> = T extends string ? never : T & { value: T };
|
||||
|
||||
function correlated<T>(value: T & not string & { value: T & not string }): Correlated<T> {
|
||||
// The outer T and the value property's T can come from different union members, unlike Correlated<T>.
|
||||
return value;
|
||||
}
|
||||
|
||||
function trueFunction<T>(value: () => (string & { value: T })): FilteredFunction<string & { value: T }> {
|
||||
// The check type always extends string, so the result is never, not a function.
|
||||
return value;
|
||||
}
|
||||
|
||||
function unionFunction<T>(value: () => ([T] | string)): FilteredFunction<[T] | string> {
|
||||
// The string union member is filtered out, so the returned function must return [T], not string.
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
//// [indexMappedTypeWithFilteredKeysWithNegationErrors.js]
|
||||
"use strict";
|
||||
function makeFunction() {
|
||||
// When T is string, FilteredFunction<T> is never, but this still returns a function.
|
||||
return () => { throw new Error(); };
|
||||
}
|
||||
const impossibleFunction = makeFunction();
|
||||
function makePair(value) {
|
||||
// The tuple elements can come from different union members, unlike the distributed FilteredPair<T>.
|
||||
return value;
|
||||
}
|
||||
const homogeneousPair = makePair(["a", 1]);
|
||||
function dependentFilter(value) {
|
||||
// For T = "a" | "b", Omitted<T> is never, so value can be "b", but DependentFilter<T> is "a".
|
||||
return value;
|
||||
}
|
||||
const onlyA = dependentFilter("b");
|
||||
function unfiltered(value) {
|
||||
// value can still belong to U, whose members are excluded from Filter<T, U>.
|
||||
return value;
|
||||
}
|
||||
function excludedKey(value) {
|
||||
// Excluding "c" does not prevent value from being the filtered-out key "b".
|
||||
return value;
|
||||
}
|
||||
function unrelatedKey(value) {
|
||||
// value is not constrained to keyof T and may name a property T does not have.
|
||||
return value;
|
||||
}
|
||||
function remappedKey(value) {
|
||||
// For T with just "a" and "b", neither key accepts their union, so no keys survive.
|
||||
return value;
|
||||
}
|
||||
function dependentKey(value) {
|
||||
// For T = { a: number; b: number }, value can be "b", but only "a" survives the per-key filter.
|
||||
return value;
|
||||
}
|
||||
function repeated(value) {
|
||||
// value can mix different union members in its two T positions, unlike Repeated<T>.
|
||||
return value;
|
||||
}
|
||||
const same = repeated("a-b");
|
||||
function correlated(value) {
|
||||
// The outer T and the value property's T can come from different union members, unlike Correlated<T>.
|
||||
return value;
|
||||
}
|
||||
function trueFunction(value) {
|
||||
// The check type always extends string, so the result is never, not a function.
|
||||
return value;
|
||||
}
|
||||
function unionFunction(value) {
|
||||
// The string union member is filtered out, so the returned function must return [T], not string.
|
||||
return value;
|
||||
}
|
||||
Vendored
+283
@@ -0,0 +1,283 @@
|
||||
//// [tests/cases/compiler/indexMappedTypeWithFilteredKeysWithNegationErrors.ts] ////
|
||||
|
||||
=== indexMappedTypeWithFilteredKeysWithNegationErrors.ts ===
|
||||
type FilteredFunction<T> = T extends string ? never : () => T;
|
||||
>FilteredFunction : Symbol(FilteredFunction, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 0, 22))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 0, 22))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 0, 22))
|
||||
|
||||
function makeFunction<T>(): FilteredFunction<T> {
|
||||
>makeFunction : Symbol(makeFunction, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 0, 62))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 2, 22))
|
||||
>FilteredFunction : Symbol(FilteredFunction, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 2, 22))
|
||||
|
||||
// When T is string, FilteredFunction<T> is never, but this still returns a function.
|
||||
return () => { throw new Error(); };
|
||||
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2022.error.d.ts, --, --))
|
||||
}
|
||||
|
||||
const impossibleFunction: never = makeFunction<string>();
|
||||
>impossibleFunction : Symbol(impossibleFunction, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 7, 5))
|
||||
>makeFunction : Symbol(makeFunction, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 0, 62))
|
||||
|
||||
type FilteredPair<T> = T extends boolean ? never : [T, T];
|
||||
>FilteredPair : Symbol(FilteredPair, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 7, 57))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 9, 18))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 9, 18))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 9, 18))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 9, 18))
|
||||
|
||||
function makePair<T>(value: [T & not boolean, T & not boolean]): FilteredPair<T> {
|
||||
>makePair : Symbol(makePair, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 9, 58))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 11, 18))
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 11, 21))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 11, 18))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 11, 18))
|
||||
>FilteredPair : Symbol(FilteredPair, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 7, 57))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 11, 18))
|
||||
|
||||
// The tuple elements can come from different union members, unlike the distributed FilteredPair<T>.
|
||||
return value;
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 11, 21))
|
||||
}
|
||||
|
||||
const homogeneousPair: [string, string] | [number, number] = makePair<string | number>(["a", 1]);
|
||||
>homogeneousPair : Symbol(homogeneousPair, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 16, 5))
|
||||
>makePair : Symbol(makePair, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 9, 58))
|
||||
|
||||
type Omitted<T> = "a" extends T ? never : "b";
|
||||
>Omitted : Symbol(Omitted, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 16, 97))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 18, 13))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 18, 13))
|
||||
|
||||
type DependentFilter<T> = T extends Omitted<T> ? never : T;
|
||||
>DependentFilter : Symbol(DependentFilter, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 18, 46))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 19, 21))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 19, 21))
|
||||
>Omitted : Symbol(Omitted, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 16, 97))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 19, 21))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 19, 21))
|
||||
|
||||
function dependentFilter<T>(value: T & not Omitted<T>): DependentFilter<T> {
|
||||
>dependentFilter : Symbol(dependentFilter, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 19, 59))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 21, 25))
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 21, 28))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 21, 25))
|
||||
>Omitted : Symbol(Omitted, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 16, 97))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 21, 25))
|
||||
>DependentFilter : Symbol(DependentFilter, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 18, 46))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 21, 25))
|
||||
|
||||
// For T = "a" | "b", Omitted<T> is never, so value can be "b", but DependentFilter<T> is "a".
|
||||
return value;
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 21, 28))
|
||||
}
|
||||
|
||||
const onlyA: "a" = dependentFilter<"a" | "b">("b");
|
||||
>onlyA : Symbol(onlyA, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 26, 5))
|
||||
>dependentFilter : Symbol(dependentFilter, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 19, 59))
|
||||
|
||||
type Filter<T, U> = T extends U ? never : T;
|
||||
>Filter : Symbol(Filter, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 26, 51))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 28, 12))
|
||||
>U : Symbol(U, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 28, 14))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 28, 12))
|
||||
>U : Symbol(U, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 28, 14))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 28, 12))
|
||||
|
||||
function unfiltered<T, U>(value: T): Filter<T, U> {
|
||||
>unfiltered : Symbol(unfiltered, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 28, 44))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 30, 20))
|
||||
>U : Symbol(U, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 30, 22))
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 30, 26))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 30, 20))
|
||||
>Filter : Symbol(Filter, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 26, 51))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 30, 20))
|
||||
>U : Symbol(U, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 30, 22))
|
||||
|
||||
// value can still belong to U, whose members are excluded from Filter<T, U>.
|
||||
return value;
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 30, 26))
|
||||
}
|
||||
|
||||
type FilteredKeys<T> = {
|
||||
>FilteredKeys : Symbol(FilteredKeys, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 33, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 35, 18))
|
||||
|
||||
[K in keyof T as K extends "b" ? never : K]: T[K]
|
||||
>K : Symbol(K, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 36, 5))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 35, 18))
|
||||
>K : Symbol(K, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 36, 5))
|
||||
>K : Symbol(K, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 36, 5))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 35, 18))
|
||||
>K : Symbol(K, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 36, 5))
|
||||
|
||||
};
|
||||
|
||||
function excludedKey<T>(value: keyof T & not "c"): keyof FilteredKeys<T> {
|
||||
>excludedKey : Symbol(excludedKey, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 37, 2))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 39, 21))
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 39, 24))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 39, 21))
|
||||
>FilteredKeys : Symbol(FilteredKeys, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 33, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 39, 21))
|
||||
|
||||
// Excluding "c" does not prevent value from being the filtered-out key "b".
|
||||
return value;
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 39, 24))
|
||||
}
|
||||
|
||||
function unrelatedKey<T>(value: string & not "b"): keyof FilteredKeys<T> {
|
||||
>unrelatedKey : Symbol(unrelatedKey, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 42, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 44, 22))
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 44, 25))
|
||||
>FilteredKeys : Symbol(FilteredKeys, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 33, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 44, 22))
|
||||
|
||||
// value is not constrained to keyof T and may name a property T does not have.
|
||||
return value;
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 44, 25))
|
||||
}
|
||||
|
||||
type RemappedKeys<T> = {
|
||||
>RemappedKeys : Symbol(RemappedKeys, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 47, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 49, 18))
|
||||
|
||||
[K in keyof T as ("a" | "b") extends K ? K : never]: T[K]
|
||||
>K : Symbol(K, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 50, 5))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 49, 18))
|
||||
>K : Symbol(K, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 50, 5))
|
||||
>K : Symbol(K, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 50, 5))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 49, 18))
|
||||
>K : Symbol(K, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 50, 5))
|
||||
|
||||
};
|
||||
|
||||
function remappedKey<T extends { a: unknown; b: unknown }>(
|
||||
>remappedKey : Symbol(remappedKey, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 51, 2))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 53, 21))
|
||||
>a : Symbol(a, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 53, 32))
|
||||
>b : Symbol(b, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 53, 44))
|
||||
|
||||
value: keyof T & not "c"
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 53, 59))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 53, 21))
|
||||
|
||||
): keyof RemappedKeys<T> {
|
||||
>RemappedKeys : Symbol(RemappedKeys, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 47, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 53, 21))
|
||||
|
||||
// For T with just "a" and "b", neither key accepts their union, so no keys survive.
|
||||
return value;
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 53, 59))
|
||||
}
|
||||
|
||||
type DependentKeys<T> = {
|
||||
>DependentKeys : Symbol(DependentKeys, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 58, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 60, 19))
|
||||
|
||||
[K in keyof T as K extends Omitted<K> ? never : K]: T[K]
|
||||
>K : Symbol(K, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 61, 5))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 60, 19))
|
||||
>K : Symbol(K, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 61, 5))
|
||||
>Omitted : Symbol(Omitted, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 16, 97))
|
||||
>K : Symbol(K, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 61, 5))
|
||||
>K : Symbol(K, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 61, 5))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 60, 19))
|
||||
>K : Symbol(K, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 61, 5))
|
||||
|
||||
};
|
||||
|
||||
function dependentKey<T>(value: keyof T & not Omitted<keyof T>): keyof DependentKeys<T> {
|
||||
>dependentKey : Symbol(dependentKey, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 62, 2))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 64, 22))
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 64, 25))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 64, 22))
|
||||
>Omitted : Symbol(Omitted, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 16, 97))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 64, 22))
|
||||
>DependentKeys : Symbol(DependentKeys, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 58, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 64, 22))
|
||||
|
||||
// For T = { a: number; b: number }, value can be "b", but only "a" survives the per-key filter.
|
||||
return value;
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 64, 25))
|
||||
}
|
||||
|
||||
type Repeated<T extends string> = T extends "skip" ? never : `${T}-${T}`;
|
||||
>Repeated : Symbol(Repeated, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 67, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 69, 14))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 69, 14))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 69, 14))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 69, 14))
|
||||
|
||||
function repeated<T extends string>(value: `${T & not "skip"}-${T & not "skip"}`): Repeated<T> {
|
||||
>repeated : Symbol(repeated, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 69, 73))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 71, 18))
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 71, 36))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 71, 18))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 71, 18))
|
||||
>Repeated : Symbol(Repeated, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 67, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 71, 18))
|
||||
|
||||
// value can mix different union members in its two T positions, unlike Repeated<T>.
|
||||
return value;
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 71, 36))
|
||||
}
|
||||
|
||||
const same: "a-a" | "b-b" = repeated<"a" | "b">("a-b");
|
||||
>same : Symbol(same, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 76, 5))
|
||||
>repeated : Symbol(repeated, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 69, 73))
|
||||
|
||||
type Correlated<T> = T extends string ? never : T & { value: T };
|
||||
>Correlated : Symbol(Correlated, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 76, 55))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 78, 16))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 78, 16))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 78, 16))
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 78, 53))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 78, 16))
|
||||
|
||||
function correlated<T>(value: T & not string & { value: T & not string }): Correlated<T> {
|
||||
>correlated : Symbol(correlated, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 78, 65))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 80, 20))
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 80, 23))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 80, 20))
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 80, 48))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 80, 20))
|
||||
>Correlated : Symbol(Correlated, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 76, 55))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 80, 20))
|
||||
|
||||
// The outer T and the value property's T can come from different union members, unlike Correlated<T>.
|
||||
return value;
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 80, 23))
|
||||
}
|
||||
|
||||
function trueFunction<T>(value: () => (string & { value: T })): FilteredFunction<string & { value: T }> {
|
||||
>trueFunction : Symbol(trueFunction, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 83, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 85, 22))
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 85, 25))
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 85, 49))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 85, 22))
|
||||
>FilteredFunction : Symbol(FilteredFunction, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 0, 0))
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 85, 91))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 85, 22))
|
||||
|
||||
// The check type always extends string, so the result is never, not a function.
|
||||
return value;
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 85, 25))
|
||||
}
|
||||
|
||||
function unionFunction<T>(value: () => ([T] | string)): FilteredFunction<[T] | string> {
|
||||
>unionFunction : Symbol(unionFunction, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 88, 1))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 90, 23))
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 90, 26))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 90, 23))
|
||||
>FilteredFunction : Symbol(FilteredFunction, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 0, 0))
|
||||
>T : Symbol(T, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 90, 23))
|
||||
|
||||
// The string union member is filtered out, so the returned function must return [T], not string.
|
||||
return value;
|
||||
>value : Symbol(value, Decl(indexMappedTypeWithFilteredKeysWithNegationErrors.ts, 90, 26))
|
||||
}
|
||||
|
||||
Vendored
+185
@@ -0,0 +1,185 @@
|
||||
//// [tests/cases/compiler/indexMappedTypeWithFilteredKeysWithNegationErrors.ts] ////
|
||||
|
||||
=== indexMappedTypeWithFilteredKeysWithNegationErrors.ts ===
|
||||
type FilteredFunction<T> = T extends string ? never : () => T;
|
||||
>FilteredFunction : FilteredFunction<T>
|
||||
|
||||
function makeFunction<T>(): FilteredFunction<T> {
|
||||
>makeFunction : <T>() => FilteredFunction<T>
|
||||
|
||||
// When T is string, FilteredFunction<T> is never, but this still returns a function.
|
||||
return () => { throw new Error(); };
|
||||
>() => { throw new Error(); } : () => never
|
||||
>new Error() : Error
|
||||
>Error : ErrorConstructor
|
||||
}
|
||||
|
||||
const impossibleFunction: never = makeFunction<string>();
|
||||
>impossibleFunction : never
|
||||
>makeFunction<string>() : never
|
||||
>makeFunction : <T>() => FilteredFunction<T>
|
||||
|
||||
type FilteredPair<T> = T extends boolean ? never : [T, T];
|
||||
>FilteredPair : FilteredPair<T>
|
||||
|
||||
function makePair<T>(value: [T & not boolean, T & not boolean]): FilteredPair<T> {
|
||||
>makePair : <T>(value: [T & not boolean, T & not boolean]) => FilteredPair<T>
|
||||
>value : [T & not false & not true, T & not false & not true]
|
||||
|
||||
// The tuple elements can come from different union members, unlike the distributed FilteredPair<T>.
|
||||
return value;
|
||||
>value : [T & not false & not true, T & not false & not true]
|
||||
}
|
||||
|
||||
const homogeneousPair: [string, string] | [number, number] = makePair<string | number>(["a", 1]);
|
||||
>homogeneousPair : [string, string] | [number, number]
|
||||
>makePair<string | number>(["a", 1]) : [string, string] | [number, number]
|
||||
>makePair : <T>(value: [T & not boolean, T & not boolean]) => FilteredPair<T>
|
||||
>["a", 1] : [string, number]
|
||||
>"a" : "a"
|
||||
>1 : 1
|
||||
|
||||
type Omitted<T> = "a" extends T ? never : "b";
|
||||
>Omitted : Omitted<T>
|
||||
|
||||
type DependentFilter<T> = T extends Omitted<T> ? never : T;
|
||||
>DependentFilter : DependentFilter<T>
|
||||
|
||||
function dependentFilter<T>(value: T & not Omitted<T>): DependentFilter<T> {
|
||||
>dependentFilter : <T>(value: T & not Omitted<T>) => DependentFilter<T>
|
||||
>value : T & not Omitted<T>
|
||||
|
||||
// For T = "a" | "b", Omitted<T> is never, so value can be "b", but DependentFilter<T> is "a".
|
||||
return value;
|
||||
>value : T & not Omitted<T>
|
||||
}
|
||||
|
||||
const onlyA: "a" = dependentFilter<"a" | "b">("b");
|
||||
>onlyA : "a"
|
||||
>dependentFilter<"a" | "b">("b") : "a"
|
||||
>dependentFilter : <T>(value: T & not Omitted<T>) => DependentFilter<T>
|
||||
>"b" : "b"
|
||||
|
||||
type Filter<T, U> = T extends U ? never : T;
|
||||
>Filter : Filter<T, U>
|
||||
|
||||
function unfiltered<T, U>(value: T): Filter<T, U> {
|
||||
>unfiltered : <T, U>(value: T) => Filter<T, U>
|
||||
>value : T
|
||||
|
||||
// value can still belong to U, whose members are excluded from Filter<T, U>.
|
||||
return value;
|
||||
>value : T
|
||||
}
|
||||
|
||||
type FilteredKeys<T> = {
|
||||
>FilteredKeys : FilteredKeys<T>
|
||||
|
||||
[K in keyof T as K extends "b" ? never : K]: T[K]
|
||||
};
|
||||
|
||||
function excludedKey<T>(value: keyof T & not "c"): keyof FilteredKeys<T> {
|
||||
>excludedKey : <T>(value: keyof T & not "c") => keyof FilteredKeys<T>
|
||||
>value : keyof T & not "c"
|
||||
|
||||
// Excluding "c" does not prevent value from being the filtered-out key "b".
|
||||
return value;
|
||||
>value : keyof T & not "c"
|
||||
}
|
||||
|
||||
function unrelatedKey<T>(value: string & not "b"): keyof FilteredKeys<T> {
|
||||
>unrelatedKey : <T>(value: string & not "b") => keyof FilteredKeys<T>
|
||||
>value : string & not "b"
|
||||
|
||||
// value is not constrained to keyof T and may name a property T does not have.
|
||||
return value;
|
||||
>value : string & not "b"
|
||||
}
|
||||
|
||||
type RemappedKeys<T> = {
|
||||
>RemappedKeys : RemappedKeys<T>
|
||||
|
||||
[K in keyof T as ("a" | "b") extends K ? K : never]: T[K]
|
||||
};
|
||||
|
||||
function remappedKey<T extends { a: unknown; b: unknown }>(
|
||||
>remappedKey : <T extends { a: unknown; b: unknown; }>(value: keyof T & not "c") => keyof RemappedKeys<T>
|
||||
>a : unknown
|
||||
>b : unknown
|
||||
|
||||
value: keyof T & not "c"
|
||||
>value : keyof T & not "c"
|
||||
|
||||
): keyof RemappedKeys<T> {
|
||||
// For T with just "a" and "b", neither key accepts their union, so no keys survive.
|
||||
return value;
|
||||
>value : keyof T & not "c"
|
||||
}
|
||||
|
||||
type DependentKeys<T> = {
|
||||
>DependentKeys : DependentKeys<T>
|
||||
|
||||
[K in keyof T as K extends Omitted<K> ? never : K]: T[K]
|
||||
};
|
||||
|
||||
function dependentKey<T>(value: keyof T & not Omitted<keyof T>): keyof DependentKeys<T> {
|
||||
>dependentKey : <T>(value: keyof T & not Omitted<keyof T>) => keyof DependentKeys<T>
|
||||
>value : keyof T & not Omitted<keyof T>
|
||||
|
||||
// For T = { a: number; b: number }, value can be "b", but only "a" survives the per-key filter.
|
||||
return value;
|
||||
>value : keyof T & not Omitted<keyof T>
|
||||
}
|
||||
|
||||
type Repeated<T extends string> = T extends "skip" ? never : `${T}-${T}`;
|
||||
>Repeated : Repeated<T>
|
||||
|
||||
function repeated<T extends string>(value: `${T & not "skip"}-${T & not "skip"}`): Repeated<T> {
|
||||
>repeated : <T extends string>(value: `${T & not "skip"}-${T & not "skip"}`) => Repeated<T>
|
||||
>value : `${T & not "skip"}-${T & not "skip"}`
|
||||
|
||||
// value can mix different union members in its two T positions, unlike Repeated<T>.
|
||||
return value;
|
||||
>value : `${T & not "skip"}-${T & not "skip"}`
|
||||
}
|
||||
|
||||
const same: "a-a" | "b-b" = repeated<"a" | "b">("a-b");
|
||||
>same : "a-a" | "b-b"
|
||||
>repeated<"a" | "b">("a-b") : "a-a" | "b-b"
|
||||
>repeated : <T extends string>(value: `${T & not "skip"}-${T & not "skip"}`) => Repeated<T>
|
||||
>"a-b" : "a-b"
|
||||
|
||||
type Correlated<T> = T extends string ? never : T & { value: T };
|
||||
>Correlated : Correlated<T>
|
||||
>value : T
|
||||
|
||||
function correlated<T>(value: T & not string & { value: T & not string }): Correlated<T> {
|
||||
>correlated : <T>(value: T & not string & { value: T & not string; }) => Correlated<T>
|
||||
>value : T & not string & { value: T & not string; }
|
||||
>value : T & not string
|
||||
|
||||
// The outer T and the value property's T can come from different union members, unlike Correlated<T>.
|
||||
return value;
|
||||
>value : T & not string & { value: T & not string; }
|
||||
}
|
||||
|
||||
function trueFunction<T>(value: () => (string & { value: T })): FilteredFunction<string & { value: T }> {
|
||||
>trueFunction : <T>(value: () => (string & { value: T; })) => FilteredFunction<string & { value: T; }>
|
||||
>value : () => (string & { value: T; })
|
||||
>value : T
|
||||
>value : T
|
||||
|
||||
// The check type always extends string, so the result is never, not a function.
|
||||
return value;
|
||||
>value : () => (string & { value: T; })
|
||||
}
|
||||
|
||||
function unionFunction<T>(value: () => ([T] | string)): FilteredFunction<[T] | string> {
|
||||
>unionFunction : <T>(value: () => ([T] | string)) => FilteredFunction<[T] | string>
|
||||
>value : () => ([T] | string)
|
||||
|
||||
// The string union member is filtered out, so the returned function must return [T], not string.
|
||||
return value;
|
||||
>value : () => ([T] | string)
|
||||
}
|
||||
|
||||
+96
@@ -38,3 +38,99 @@ const t1: T1 = ['b', 'c'];
|
||||
|
||||
type S1<T> = { [K in keyof T & string as K extends '_key' ? never : K]: 1 }[LocalExclude<keyof T & string, '_key'>];
|
||||
type S2<T> = { [K in string & keyof T as K extends '_key' ? never : K]: 1 }[LocalExclude<string & keyof T, '_key'>];
|
||||
|
||||
type ConditionalExclude<T, U> = T extends U ? never : T;
|
||||
|
||||
function exclude<T, U>(value: T & not U): ConditionalExclude<T, U> {
|
||||
return value;
|
||||
}
|
||||
|
||||
type Identity<T> = T;
|
||||
type AliasedExclude<T, U> = T extends U ? never : Identity<T>;
|
||||
|
||||
function aliasedExclude<T, U>(value: T & not U): AliasedExclude<T, U> {
|
||||
return value;
|
||||
}
|
||||
|
||||
function mappedExclude<T, U>(value: keyof T & not U): keyof ExcludeKey<T, U> {
|
||||
return value;
|
||||
}
|
||||
|
||||
type AliasedExcludeKey<T, U> = {
|
||||
[K in keyof T as ConditionalExclude<K, U>]: T[K]
|
||||
};
|
||||
|
||||
function aliasedMappedExclude<T, U>(value: keyof T & not U): keyof AliasedExcludeKey<T, U> {
|
||||
return value;
|
||||
}
|
||||
|
||||
type Prefixed<T extends string> = T extends "skip" ? never : `prefix${T}`;
|
||||
|
||||
function prefixed<T extends string>(value: `prefix${T & not "skip"}`): Prefixed<T> {
|
||||
return value;
|
||||
}
|
||||
|
||||
type WithSuffix<T extends string, S extends string> = T extends "skip" ? never : `prefix${T}:${S}`;
|
||||
|
||||
function withSuffix<T extends string, S extends string>(value: `prefix${T & not "skip"}:${S}`): WithSuffix<T, S> {
|
||||
return value;
|
||||
}
|
||||
|
||||
type Cased<T extends string> = Uppercase<`prefix${Lowercase<T>}`>;
|
||||
type FilteredCased<T extends string> = T extends "skip" ? never : Cased<T>;
|
||||
|
||||
function cased<T extends string>(value: Cased<T & not "skip">): FilteredCased<T> {
|
||||
return value;
|
||||
}
|
||||
|
||||
type Alternatives<T extends string> = T extends "skip" ? never : `left${T}` | `right${Uppercase<T>}`;
|
||||
|
||||
function alternatives<T extends string>(
|
||||
value: `left${T & not "skip"}` | `right${Uppercase<T & not "skip">}`
|
||||
): Alternatives<T> {
|
||||
return value;
|
||||
}
|
||||
|
||||
type Branded<T> = T extends "skip" ? never : T & { brand: true };
|
||||
|
||||
function branded<T>(value: T & not "skip" & { brand: true }): Branded<T> {
|
||||
return value;
|
||||
}
|
||||
|
||||
interface Values {
|
||||
a: 1;
|
||||
b: 2;
|
||||
skip: 3;
|
||||
}
|
||||
|
||||
type Lookup<T extends keyof Values> = T extends "skip" ? never : Values[T];
|
||||
|
||||
function lookup<T extends keyof Values>(value: Values[T & not "skip"]): Lookup<T> {
|
||||
return value;
|
||||
}
|
||||
|
||||
type PrefixedKeys<T> = {
|
||||
[K in keyof T & string as K extends "_key" ? never : `prefix${K}`]: T[K]
|
||||
};
|
||||
|
||||
function prefixedKey<T>(value: `prefix${keyof T & string & not "_key"}`): keyof PrefixedKeys<T> {
|
||||
return value;
|
||||
}
|
||||
|
||||
type FunctionResult<T> = T extends string ? never : () => T;
|
||||
|
||||
function falseFunction<T>(value: () => [T]): FunctionResult<[T]> {
|
||||
return value;
|
||||
}
|
||||
|
||||
type TupleResult<T> = T extends string ? never : [T, T];
|
||||
|
||||
function falseTuple<T>(value: [[T], [T]]): TupleResult<[T]> {
|
||||
return value;
|
||||
}
|
||||
|
||||
type Nested<T extends string> = T extends "skip" ? never : ConditionalExclude<`prefix${T}`, "prefixomit">;
|
||||
|
||||
function nested<T extends string>(value: ConditionalExclude<`prefix${T & not "skip"}`, "prefixomit">): Nested<T> {
|
||||
return value;
|
||||
}
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
// @strict: true
|
||||
|
||||
type FilteredFunction<T> = T extends string ? never : () => T;
|
||||
|
||||
function makeFunction<T>(): FilteredFunction<T> {
|
||||
// When T is string, FilteredFunction<T> is never, but this still returns a function.
|
||||
return () => { throw new Error(); };
|
||||
}
|
||||
|
||||
const impossibleFunction: never = makeFunction<string>();
|
||||
|
||||
type FilteredPair<T> = T extends boolean ? never : [T, T];
|
||||
|
||||
function makePair<T>(value: [T & not boolean, T & not boolean]): FilteredPair<T> {
|
||||
// The tuple elements can come from different union members, unlike the distributed FilteredPair<T>.
|
||||
return value;
|
||||
}
|
||||
|
||||
const homogeneousPair: [string, string] | [number, number] = makePair<string | number>(["a", 1]);
|
||||
|
||||
type Omitted<T> = "a" extends T ? never : "b";
|
||||
type DependentFilter<T> = T extends Omitted<T> ? never : T;
|
||||
|
||||
function dependentFilter<T>(value: T & not Omitted<T>): DependentFilter<T> {
|
||||
// For T = "a" | "b", Omitted<T> is never, so value can be "b", but DependentFilter<T> is "a".
|
||||
return value;
|
||||
}
|
||||
|
||||
const onlyA: "a" = dependentFilter<"a" | "b">("b");
|
||||
|
||||
type Filter<T, U> = T extends U ? never : T;
|
||||
|
||||
function unfiltered<T, U>(value: T): Filter<T, U> {
|
||||
// value can still belong to U, whose members are excluded from Filter<T, U>.
|
||||
return value;
|
||||
}
|
||||
|
||||
type FilteredKeys<T> = {
|
||||
[K in keyof T as K extends "b" ? never : K]: T[K]
|
||||
};
|
||||
|
||||
function excludedKey<T>(value: keyof T & not "c"): keyof FilteredKeys<T> {
|
||||
// Excluding "c" does not prevent value from being the filtered-out key "b".
|
||||
return value;
|
||||
}
|
||||
|
||||
function unrelatedKey<T>(value: string & not "b"): keyof FilteredKeys<T> {
|
||||
// value is not constrained to keyof T and may name a property T does not have.
|
||||
return value;
|
||||
}
|
||||
|
||||
type RemappedKeys<T> = {
|
||||
[K in keyof T as ("a" | "b") extends K ? K : never]: T[K]
|
||||
};
|
||||
|
||||
function remappedKey<T extends { a: unknown; b: unknown }>(
|
||||
value: keyof T & not "c"
|
||||
): keyof RemappedKeys<T> {
|
||||
// For T with just "a" and "b", neither key accepts their union, so no keys survive.
|
||||
return value;
|
||||
}
|
||||
|
||||
type DependentKeys<T> = {
|
||||
[K in keyof T as K extends Omitted<K> ? never : K]: T[K]
|
||||
};
|
||||
|
||||
function dependentKey<T>(value: keyof T & not Omitted<keyof T>): keyof DependentKeys<T> {
|
||||
// For T = { a: number; b: number }, value can be "b", but only "a" survives the per-key filter.
|
||||
return value;
|
||||
}
|
||||
|
||||
type Repeated<T extends string> = T extends "skip" ? never : `${T}-${T}`;
|
||||
|
||||
function repeated<T extends string>(value: `${T & not "skip"}-${T & not "skip"}`): Repeated<T> {
|
||||
// value can mix different union members in its two T positions, unlike Repeated<T>.
|
||||
return value;
|
||||
}
|
||||
|
||||
const same: "a-a" | "b-b" = repeated<"a" | "b">("a-b");
|
||||
|
||||
type Correlated<T> = T extends string ? never : T & { value: T };
|
||||
|
||||
function correlated<T>(value: T & not string & { value: T & not string }): Correlated<T> {
|
||||
// The outer T and the value property's T can come from different union members, unlike Correlated<T>.
|
||||
return value;
|
||||
}
|
||||
|
||||
function trueFunction<T>(value: () => (string & { value: T })): FilteredFunction<string & { value: T }> {
|
||||
// The check type always extends string, so the result is never, not a function.
|
||||
return value;
|
||||
}
|
||||
|
||||
function unionFunction<T>(value: () => ([T] | string)): FilteredFunction<[T] | string> {
|
||||
// The string union member is filtered out, so the returned function must return [T], not string.
|
||||
return value;
|
||||
}
|
||||
Reference in new issue
Block a user