Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

String literals not evaluate to string enum values. #22855

Closed
electricessence opened this issue Mar 24, 2018 · 6 comments
Closed

String literals not evaluate to string enum values. #22855

electricessence opened this issue Mar 24, 2018 · 6 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@electricessence
Copy link

TypeScript Version: 2.8.0

Search Terms:
string literal enum

Code

const enum TypeOfValue
{
	Boolean   = 'boolean',
	Number    = 'number',
	String    = 'string',
	Symbol    = 'symbol',
	Object    = 'object',
	Undefined = 'undefined',
	Function  = 'function'
}
if(typeof x==TypeOfValue.String) {
    // Type guard fails for string.
}

Expected behavior:
The code in the within the if block should understand that x is a string.

Actual behavior:
The if block is unaware of the type.

@MartinJohns
Copy link
Contributor

To expand on this, the same behavior happens with matching string literal types.

type TypeOfValue = 'boolean' | 'number' | 'string' | 'symbol' | 'object' | 'undefined' | 'function'

const TypeOfValueLookup: { readonly [P in TypeOfValue]: P } = {
    boolean: 'boolean',
    number: 'number',
    string: 'string',
    symbol: 'symbol',
    object: 'object',
    undefined: 'undefined',
    function: 'function'
}

if (typeof x === TypeOfValueLookup.string) {
    // x is not narrow to type string here.
}

@MartinJohns
Copy link
Contributor

@electricessence: As a workaround you could use a custom type-guard function with function overloading:

function isTypeOf(value: any, type: TypeOfValue.Boolean): value is boolean;
function isTypeOf(value: any, type: TypeOfValue.Number): value is number;
function isTypeOf(value: any, type: TypeOfValue.String): value is string;
function isTypeOf(value: any, type: TypeOfValue.Symbol): value is symbol;
function isTypeOf(value: any, type: TypeOfValue.Object): value is object;
function isTypeOf(value: any, type: TypeOfValue.Undefined): value is undefined;
function isTypeOf(value: any, type: TypeOfValue.Function): value is Function;
function isTypeOf(value: any, type: TypeOfValue) {
    return typeof value === type;
}

if (isTypeOf(x, TypeOfValue.String)) {
    // x is inferred to be a string here.
} else if (isTypeOf(x, TypeOfValue.Number)) {
    // x is inferred to be a boolean here.
}

@electricessence
Copy link
Author

@MartinJohns yeah I know that I can use custom type guards but that's what I'm trying to get away from when it's unnecessary. I have had success with building a virtual enum by declaring exported constants each as the string literal types. But I was hoping for the same behavior from enums.

@electricessence
Copy link
Author

What I like about the string enum types is that they function as both a type and as set of constants.

@RyanCavanaugh RyanCavanaugh added the Working as Intended The behavior described is the intended behavior; this is not a bug label Mar 26, 2018
@RyanCavanaugh
Copy link
Member

String enums are intentionally opaque; see #17690. The namespace alternate pattern is available if you want non-opaque literal values.

@electricessence
Copy link
Author

@RyanCavanaugh ok. I actually was using that pattern before. Thought it was more elegant to use enums.

@microsoft microsoft locked and limited conversation to collaborators Jul 25, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

3 participants