Skip to content

Type narrow not worked with this union type. #61701

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

Closed
Mng12345 opened this issue May 15, 2025 · 2 comments
Closed

Type narrow not worked with this union type. #61701

Mng12345 opened this issue May 15, 2025 · 2 comments
Labels
Duplicate An existing issue was already created

Comments

@Mng12345
Copy link

πŸ”Ž Search Terms

type narrow

πŸ•— Version & Regression Information

TypeScript 5.8.3

⏯ Playground Link

https://www.typescriptlang.org/play/?#code/HYQwtgpgzgDiDGEAEFgFcxSQbwFBIJQA8YB7AJwBcl5TgprUMkAlUgdwDEBLAG0ojkAKgE8YyPISlIAksHi80AE2hIAvEgCMAGnzSCAOVKU5C5ao0AmXfoIAhCJXYRU6pAGYbto5QdOXwG4ALF76dtwA5kIAFiCBGgCsodLhEQCCwEoAogCOaCC8MXFuAGzJUgAy0FBF8UgA7OWEVVBQGdl5BbVuABxNBLn5vG4AnP1IPoMFbpoADHoEAL64y7iUYshG5GAFPPyCouJuTJgAdGxcfALCG6dTwwA+KOhnF3vXhxCnk52PzxhQc4cd4HW6pbpPE6At5XUHiU4tGqxQKQl7Q4Gwm7w1Lte4Q-6vDH7LFfRG4361XBrDZITgUMBuSSENDcJQALiQDHI3GAEWSADNuBBeEoAKqsgD8HK5PL5CyQguJnw5Wx2vBBJOSADcCmgIBymfp1uIOQByQVECBKU3jHWKCBSpAvABGgiQTxlvNtuogyqQppdglN7v9noipvlixDhukxv1-sFwut40TIvFSkdYcjK2j8pZ7M5lG5XvlqbFkulRdlAsxfqhQMuSrBjmcrlRAIbGs+32MflbwGSvAg-MojsD5GS3Ii0VHHPHOaeMfzleLcqkZfTmarJfXtY2HPrMKb8NMihUWHbhMbH1uPlP5ig2p9foDGFd5GDT1NYZt8rteq3VcVipWh6GocgIDybgIKURl5QgqCYI5Is9WSSBWhACJ41NShom4LAyyQfCkAQlkYNOCNllAhgFXpNw0EyYceStJAQCwOlthDBiVEFYArVwIdwLQIcoA5FgIFocglAAHjDbRWOAEQAD4qW4fkkAACn5Oi1F0pBuKYvilAAShweDhIsHBlijYUoGQNTNO07ZTkVG8jl0jRDyJNyvj7AJ3SeJywBcvd3L0rzrzhL4fD81BTJjcgLKwDQY13JN0w5ABtUjoKtABdcYhxHLKcpggr5SkKcZxKyCyPy7MbN4OyiPUrT6RC49kA8gl0UiklTnvc8Ato5zXKi9RwrRTtQui4xBugeLzJEuDbAVIU01ZGrEPy717S2uqlDyhqUCaiR5Wo6gxpJNwgo6nykAAegepA41IdSrs+IisFVXYZvOugaP-LqRuCoHHue6JBGQXDkCCzlolIYTYNiLAYHIUhxCoIUsDepAgfk500GobhKG-J1jFOKlliAA

πŸ’» Code

namespace enums {
    export const enum RowFilterType {
        Includes = 1,
        NotIncludes = 2,
        Between = 3,
        NotBetween = 4,
        BigThan = 5,
        BigAndEqualThan = 6,
        LessThan = 7,
        LessAndEqualThan = 8,
        Equal = 9,
        NotEqual = 10
    }
}

type NormalFilterType = enums.RowFilterType.Equal | enums.RowFilterType.NotEqual | enums.RowFilterType.BigThan | enums.RowFilterType.LessThan | enums.RowFilterType.BigAndEqualThan | enums.RowFilterType.LessAndEqualThan

type Form = {
    uid: string,
    fieldUid?: string,
    filterType: NormalFilterType,
    value: {
        type: 'fixed',
        value?: number | string,
        valueType: 'number' | 'string'
    } | {
        type: 'field',
        fieldUid?: string
    }
} | {
    uid: string,
    fieldUid?: string,
    filterType: enums.RowFilterType.Between | enums.RowFilterType.NotBetween,
    left?: number,
    right?: number
} | {
    uid: string,
    fieldUid?: string,
    filterType: enums.RowFilterType.Includes | enums.RowFilterType.NotIncludes,
    valueType: 'number' | 'string',
    value?: string
}

const required = {
    required: true,
    message: 'this field is required.'
}
const form = undefined as Form | undefined
let rules: Record<string, any>

if (form === undefined) {
    rules = {}
} else if (form.filterType === enums.RowFilterType.Between || form.filterType === enums.RowFilterType.NotBetween) {
    rules = {
        fieldUid: [required],
        left: [required],
        right: [required]
    }
} else if (form.filterType === enums.RowFilterType.Includes || form.filterType === enums.RowFilterType.NotIncludes) {
    rules = {
        fieldUid: [required],
        value: [required]
    }
} else {
    const filterType = form.filterType // typeof filterType is NormalFilterType
    const value = form.value // here the form should has properties of value, but it's not.

}

πŸ™ Actual behavior

See the line at 66, the type of form should be narrowed in this switch, but it's not.

πŸ™‚ Expected behavior

The type of form should be narrowed.

Additional information about the issue

No response

@MartinJohns
Copy link
Contributor

MartinJohns commented May 15, 2025

I'll never understand why people don't try to minimize their demo and keep a lot of pointless noisy code. :-/

Regardless, this is a duplicate of #31404.


The simple workaround is to not have unions as discriminators:

type Form = {
    uid: string,
    fieldUid?: string,
    filterType: NormalFilterType,
    value: {
        type: 'fixed',
        value?: number | string,
        valueType: 'number' | 'string'
    } | {
        type: 'field',
        fieldUid?: string
    }
} | {
    uid: string,
    fieldUid?: string,
    filterType: enums.RowFilterType.Between,
    left?: number,
    right?: number
} | {
    uid: string,
    fieldUid?: string,
    filterType: enums.RowFilterType.NotBetween,
    left?: number,
    right?: number
} | {
    uid: string,
    fieldUid?: string,
    filterType: enums.RowFilterType.Includes,
    valueType: 'number' | 'string',
    value?: string
} | {
    uid: string,
    fieldUid?: string,
    filterType: enums.RowFilterType.NotIncludes,
    valueType: 'number' | 'string',
    value?: string
}

Or using a helper type using distributed conditional types to avoid the duplication:

type Unionize<K extends string, V, T> = V extends any ? ({ [P in K]: V } & T) : never

type Form = {
    uid: string,
    fieldUid?: string,
    filterType: NormalFilterType,
    value: {
        type: 'fixed',
        value?: number | string,
        valueType: 'number' | 'string'
    } | {
        type: 'field',
        fieldUid?: string
    }
} | Unionize<"filterType", enums.RowFilterType.Between | enums.RowFilterType.NotBetween, {
        uid: string,
        fieldUid?: string,
        left?: number,
        right?: number
    }
> | Unionize<"filterType", enums.RowFilterType.Includes | enums.RowFilterType.NotIncludes, {
        uid: string,
        fieldUid?: string,
        valueType: 'number' | 'string',
        value?: string
    }
>

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label May 15, 2025
@typescript-bot
Copy link
Collaborator

This issue has been marked as "Duplicate" and has seen no recent activity. It has been automatically closed for house-keeping purposes.

@typescript-bot typescript-bot closed this as not planned Won't fix, can't repro, duplicate, stale May 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

4 participants