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

No error when type guard claims the object will have a certain value at a key passed as a string param, but doesn't work. #17568

Closed
krryan opened this issue Aug 2, 2017 · 4 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@krryan
Copy link

krryan commented Aug 2, 2017

Came across this while trying to come up with a workaround for #17567 .

TypeScript Version: 2.4.0-dev.20170607

Code

type A = {
    [index: string]: [number, number] | null;
}
const value: A = { foo: [42, 42] };

function hasField(value: A, field: keyof A): value is { [field]: [number, number] } {
    return value[field] !== undefined && value[field] !== null;
}

if (hasField(value, 'foo')) {
    value.foo;
}

Expected behavior:
Ideally, value.foo has type [number, number], but if not, then an error on value is { [field]: [number, number] } saying that this kind of type guard does not work.

Actual behavior:
No errors for the hasField function at all, but value has type {} within the if (hasField(value, 'foo')) block, resulting in an error on value.foo stating that “Property foo does not exist on type {}.”

Note that the behavior is nearly identical if you have

type A = {
    foo?: [number, number] | null;
    bar?: [number, number] | null;
}

In this case, hasField still has a return value (according to VS Code intellisense) of value is {}, and value.foo has a type of [number, number] | null | undefined. So the indexed definition of A doesn't actually affect this.

@DanielRosenwasser
Copy link
Member

DanielRosenwasser commented Aug 4, 2017

{ [field]: [number, number] } is not valid syntax. We've discussed something like it before, but what you probably meant was

{ [K in typeof field]: [number, number] }

or

Record<typeof field, [number, number]>

But I think altogether this is going down the wrong path. You may want something closer to

function hasField<K extends string>(value: A, field: K): value is A & Record<K, [number, number]> {
    return value[field] !== undefined && value[field] !== null;
}

@DanielRosenwasser DanielRosenwasser added the Working as Intended The behavior described is the intended behavior; this is not a bug label Aug 4, 2017
@krryan
Copy link
Author

krryan commented Aug 5, 2017

Right, that's fine—the bug isn't that it doesn't work, the bug is that there is no error telling you that it doesn't work. If that's not valid syntax, there should be an error saying so, rather than leaving users to find out on their own that the type guard doesn't do what they think it does.

@aluanhaddad
Copy link
Contributor

aluanhaddad commented Aug 5, 2017

It seems that some fairly arbitrarily complex expressions are tolerated in the key position of an object literal type that is the object of an is clause.

The following is legal

type A = {
    [index: string]: [number, number] | null;
}
const value: A = { foo: [42, 42] };

function hasField(value: A, field: keyof A): value is {
    [function ns() {
        const x = new class { protected static readonly s: 1 = 'hello' }(12345);
    }()]: [number, number]
} {
    return value[field] !== undefined && value[field] !== null;
}

@mhegazy
Copy link
Contributor

mhegazy commented Aug 21, 2017

Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.

@mhegazy mhegazy closed this as completed Aug 21, 2017
@microsoft microsoft locked and limited conversation to collaborators Jun 14, 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

4 participants