Repository navigation
the types 'T' and (anything else) have no overlap #32768
Description
Activity
My use-case approximates to the following:
const isNum = (v: unknown) => { if (typeof v !== 'number') throw new Error('Not a number'); return v; }; const isString = (v: unknown) => { if (typeof v !== 'string') throw new Error('Not a string'); return v; }; function makeExampleValue<T>(validator: (v: unknown) => T): T { if (parser === isNum) return 42; if (parser === isString) return 'something'; throw new Error('unknown type'); }
I'm considering restructuring to avoid the need for what is effectively a switch in a monolith function, but the reported error is incorrect in any case.
T extends unknown?AnyhowStep that works, so I guess I'm confused why
<T>and<T extends unknown>are different (i.e. why isn'textends unknownthe default assumption?)If it can't infer
T, it should default tounknownin your case (since you didn't specify a constraint type).As for why you need to explicitly add
extends unknownfor your equality check to work, even thoughextends unknownshould be implicit...¯\(ツ)/¯
RyanCavanaugh commented
on Aug 9, 2019 MemberMore actionsDaniel Rosenwasser (@DanielRosenwasser) what's the reasoning behind the current comparability rules with type parameters?
jack-williams commented
on Aug 9, 2019 CollaboratorMore actionsAs for why you need to explicitly add extends unknown for your equality check to work, even though extends unknown should be implicit
Without an explicit constraint I think the default constraint used is the empty object type (if you do
extends {}you get the same result as with no constraint).const constraint = getConstraintOfType(<TypeVariable>source); if (!constraint || (source.flags & TypeFlags.TypeParameter && constraint.flags & TypeFlags.Any)) { // A type variable with no constraint is not related to the non-primitive object type. if (result = isRelatedTo(emptyObjectType, extractTypesOfKind(target, ~TypeFlags.NonPrimitive))) { errorInfo = saveErrorInfo; return result; } }
I'm wondering if this was just a missed case in #30637?
Reacted by AnyhowStepDanielRosenwasser commented
on Aug 9, 2019 MemberMore actionsRyan Cavanaugh (@RyanCavanaugh)
numberis not comparable toT, andTisn't comparable tonumber(becauseunknown-T's constraint - isn't comparable tonumber).We have another issue open about this, but if you tried to "fix" it, you might end up with weird behavior where two unrelated type parameters
TandUcan be checked for equality. While it's not unsound, it allows questionable code.RyanCavanaugh commented
on Aug 12, 2019 MemberMore actionsDaniel Rosenwasser (@DanielRosenwasser)
because unknown - T's constraint - isn't comparable to number
unknownis comparable tonumber, and the example works ifTis explicit constrained tounknown(which should (???) be a no-op by my understanding).DanielRosenwasser commented
on Aug 12, 2019 MemberMore actionsunknownis comparable tonumberIt's actually the other way around -
numberis comparable tounknown. Comparability is still a unidirectional relationship that we happen to apply in two directions.and the example works if
Tis explicit constrained tounknown(which should (???) be a no-op by my understanding).I would consider that a bug, and I've opened #32814 to track it. I would guess it's likely either a bug in our
getApparentTypelogic, or in the way we get implicit constraints, or we have some weird specialunknowntype we're not doing the right thing with.- addedDuplicateAn existing issue was already createdAn existing issue was already createdand removedBugA bug in TypeScriptA bug in TypeScript
on Aug 12, 2019 RyanCavanaugh commented
on Aug 12, 2019 MemberMore actionsWe're going to track this at #32814 for clarity
typescript-bot commented
on Aug 15, 2019 ContributorMore actionsThis issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes.
Without an explicit constraint I think the default constraint used is the empty object type
FYI, the default base constraint is
unknownnowadays - we swapped a few releases ago.jack-williams commented
on Aug 15, 2019 CollaboratorMore actionsYeah I knew the design had changed, but I wasn't sure if a case had been missed. That code looked related, though tbh, I'm not really sure what's going on.
- locked as resolved and limited conversation to collaborators
on Oct 21, 2025
TypeScript Version: 3.5.3
Search Terms:
Code
Expected behavior:
No error;
checkreturnstrueif givennum(or an alias of it), andfalseotherwise.Actual behavior:
I observed this in a slightly more complex case but with the same idea:
Playground Link:
https://www.typescriptlang.org/play/#code/MYewdgzgLgBGCuBbGBeGBGA3AKAGbzGCgEtwZgALAU2AGsAeAFQD4AKADwC4ZGBKGAN7YYMAE5Uo8UWBjtUKNAkQ4Avtko1arJb0xA