Home > database >  How to narrow type to object and exclude boolean type?
How to narrow type to object and exclude boolean type?

Time:02-11

I am stuck in simple example, tried different tricks to narrow type but TS giving me errors. Consider following example:

interface IObject {
    someField: string
}

interface ISomething {
    inner:  IObject | boolean
}

function returnValue(s: string, smth: ISomething): string {
    if (s === 'inner')
        return smth[s].someField
    else 
        return ''
}

Playground link

How would you tell TS that smth['inner'] is of type IObject, excluding boolean type so TS won't error: Property 'someField' does not exist on type 'boolean | IObject'. Property 'someField' does not exist on type 'false'.(2339)

CodePudding user response:

Just add an extra condition statement:

interface IObject {
    someField: string
}

interface ISomething {
    inner: IObject | boolean
}

function returnValue(s: string, smth: ISomething) {
    if (s === 'inner') {
        const value = smth[s];
      // Or typeof value === 'object'
        if (typeof value !== 'boolean') {
            return value.someField
        }
    }

    return ''
}

Playground

I think this is a good place to use function overloadings. COnsider this example:

interface IObject<SomeField> {
    someField: SomeField
}

interface ISomething<T> {
    inner: IObject<T> | boolean
}

function returnValue(s: 'inner', smth: { inner: boolean }): ''
function returnValue<SomeField extends string>(s: 'inner', smth: ISomething<SomeField>): SomeField
function returnValue(s: string, smth: ISomething<string>): ''
function returnValue(s: string, smth: ISomething<string>) {
    if (s === 'inner') {
        const value = smth[s];
        if (typeof value !== 'boolean') {
            return value.someField
        }
    }

    return ''
}

const result1 = returnValue('inner', { inner: { someField: 'hello' } }) // "hello"
const result2 = returnValue('inner', { inner: true }) // ""
const result3 = returnValue('other', { inner: true }) // ""

Playground

CodePudding user response:

(<ISomething>smth['inner']).someField

This should work

You can check for type of if(smth['inner'] instanceof boolean)

Then you can write if statements with that

  • Related