I would like the casting of a string at runtime to return a falsey value if the type is mismatched. Namely, when I run the following with [email protected]
, I encounter unexpected results:
$ ts-node
> 0 as 'B' | 'C' | 'D' || 'foo' // ✅ throws precompiler error as expected
--------------
> '' as 'B' | 'C' | 'D' || 'foo' // ✅ prints 'foo' as expected
'foo'
> undefined as 'B' | 'C' | 'D' || 'foo' // ✅ prints 'foo' as expected
'foo'
> null as 'B' | 'C' | 'D' || 'foo' // ✅ prints 'foo' as expected
'foo'
> 'B' as 'B' | 'C' | 'D' || 'foo' // ✅ prints 'B' as expected
'B'
> 'A' as 'B' | 'C' | 'D' || 'foo' // ❌ prints 'A' instead of 'foo' <-- UNEXPECTED
'A'
I clearly misunderstand how casting works, but how do I implement the logic I am trying to achieve where I expected 'A' as 'B' | 'C' | 'D'
to return a falsey value?
CodePudding user response:
as
is a type assertion, it does not have a runtime effect. You need to do some manual checking of the value instead. Something like:
const allowed = new Set(['B', 'C', 'D']);
const input: string = 'A';
const value = allowed.has(input) ? input : 'foo';
You then can assert that value is 'B' | 'C' | 'D' | 'foo'
using as
.
Playground (runnable)
Playground using type-fu to not repeat literals
CodePudding user response:
The "cleanest" way to work with unknown literals in my opinion is using a type guard.
type YourLiteralType = 'B' | 'C' | 'D'
// Important part is the return type, and returning a boolean value
function isYourLiteralType(input: unknown): input is YourLiteralType {
return input === 'B' || input === 'C' || input === 'D'
}
const a = 'A'
// Works with ifs
if (isYourLiteralType(a)) {
// a is "casted" to YourLiteralType
}
function doSomethingWithYourLiteralType(input: YourLiteralType) {
// Raises a compiler error if not called with the appropriate type
}
// Also works with ternaries
const x = isYourLiteralType(a) ? doSomethingWithYourLiteralType(a) : undefined