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

Type guards not compatible with noImplicitAny #213

Open
thodoo opened this issue Nov 9, 2022 · 1 comment · May be fixed by #243
Open

Type guards not compatible with noImplicitAny #213

thodoo opened this issue Nov 9, 2022 · 1 comment · May be fixed by #243
Labels
bug Something isn't working pr requested

Comments

@thodoo
Copy link

thodoo commented Nov 9, 2022

Hi, thanks for this nice project. We have been using it for some quite complex API responses and found an edge case:

Repro (simplified - the real case has a union of two interfaces):

export interface SomeInterface {
  prop: { key1: string } | { key2: string };
}

Type guard:

export function isSomeInterface(obj: unknown): obj is SomeInterface {
    const typedObj = obj as SomeInterface
    return (
        (typedObj !== null &&
            typeof typedObj === "object" ||
            typeof typedObj === "function") &&
        ((typedObj["prop"] !== null &&
            typeof typedObj["prop"] === "object" ||
            typeof typedObj["prop"] === "function") &&
            typeof typedObj["prop"]["key1"] === "string" ||
            (typedObj["prop"] !== null &&
                typeof typedObj["prop"] === "object" ||
                typeof typedObj["prop"] === "function") &&
            typeof typedObj["prop"]["key2"] === "string")
    )
}

Typescript with strict settings complains about implicit any:

error TS7053: Element implicitly has an 'any' type because expression of type '"key1"' can't be used to index type '{ key1: string; } | { key2: string; }'.
  Property 'key1' does not exist on type '{ key1: string; } | { key2: string; }'.

             typeof typedObj["prop"]["key1"] === "string" ||
                       ~~~~~~~~~~~~~~~~~~~~~~~~

error TS7053: Element implicitly has an 'any' type because expression of type '"key2"' can't be used to index type '{ key1: string; } | { key2: string; }'.
  Property 'key2' does not exist on type '{ key1: string; } | { key2: string; }'.

             typeof typedObj["prop"]["key2"] === "string")

Possible solution: adding "key1" in typedObj["prop"]:

export function isSomeInterface(obj: unknown): obj is SomeInterface {
    const typedObj = obj as SomeInterface
    return (
        (typedObj !== null &&
            typeof typedObj === "object" ||
            typeof typedObj === "function") &&
        ((typedObj["prop"] !== null &&
            typeof typedObj["prop"] === "object" ||
            typeof typedObj["prop"] === "function") &&
            "key1" in typedObj["prop"] &&
            typeof typedObj["prop"]["key1"] === "string" ||
            (typedObj["prop"] !== null &&
                typeof typedObj["prop"] === "object" ||
                typeof typedObj["prop"] === "function") &&
            "key2" in typedObj["prop"] &&
            typeof typedObj["prop"]["key2"] === "string")
    )
}
@rhys-vdw rhys-vdw added the bug Something isn't working label Nov 10, 2022
@rhys-vdw
Copy link
Owner

Thank you, this is in deed an edge case. Your solution looks good. PR welcome!

@Mojashi Mojashi linked a pull request Mar 1, 2024 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working pr requested
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants