Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Narrow `unknown` to an object with a string-field without using `any`

Tags:

typescript

i'm trying to validate data that my application receives. a short example is the following:

function getField(data:unknown):string {
    if (typeof data !== 'object') {
        throw new Error('e1');
    }

    if (data == null) {
        throw new Error('e2');
    }

    const { field } = data;

    if (typeof field !== 'string') {
        throw new Error('e3');
    }

    return field;
}

i need to extract a string-field from the data. the code should throw if the shape of the data is invalid. the problem is, the above code does not typecheck. it fails with "Property 'field' does not exist on type '{}'.". i know i can add some any and it will work, but i'm trying to do this without any, in a type-safe way.

like image 374
gabor Avatar asked Nov 25 '19 14:11

gabor


1 Answers

There is a suggestion to allow the in type guard to asset the existence of properties but it is not implemented (GH)

You can use a type assertion which should be safe enough (const { field } = data as { field: unknown };) or you can use a custom type guard to check for the existence of the property:

function hasProp<K extends PropertyKey>(data: object, prop: K): data is Record<K, unknown> {
    return prop in data;
}
function getField(data: unknown): string {
    if (typeof data !== 'object') {
        throw new Error('e1');
    }

    if (data == null) {
        throw new Error('e2');
    }
    if (!hasProp(data, 'field')) {
        throw new Error('field does not exist');
    }
    const { field } = data;

    if (typeof field !== 'string') {
        throw new Error('e3');
    }

    return field;
}

Playground Link

Note Since you are throwing exceptions, you might use the new assertion syntax: Playground Link

like image 111
Titian Cernicova-Dragomir Avatar answered Sep 28 '22 05:09

Titian Cernicova-Dragomir