doup
doup

Reputation: 911

Validate property based on another property keys

I would like to improve the type-checking of the following object:

interface Config {
    fields: Record<string, unknown>;
    table: { id: string }[];
}

const config: Config = {
    fields: {
        id: {}
    },
    table: [
        { id: 'id' },
        { id: 'name' },
    ]
};

The part I'm struggling with is that I want to type-check that the table object id should match a key in fields. If table > id is not present in fields keys, then it should error. So:

Is this possible? Plan B is to do this check at runtime.

Upvotes: 2

Views: 232

Answers (3)

Tobias S.
Tobias S.

Reputation: 23885

It is not possible (yet) to create a standalone type which can do validation like that. But generic types are powerful enough to achieve this. Generic types for validation are best used in combination with a function.

function useConfig<F>(config: { fields: F, table: { id: keyof F }[]}) {}

In this function we have the generic type F which holds information about the object we pass with the fields property. We can then use keyof F inside table.

Some tests to validate the result:

useConfig({
    fields: {
        id: {}
    },
    table: [
        { id: 'id' }
    ]
})
// works

useConfig({
    fields: {
        id: {}
    },
    table: [
        { id: 'id' },
        { id: 'name' }
    ]
})
// error

useConfig({
    fields: {
        id: {},
        name: {}
    },
    table: [
        { id: 'id' },
        { id: 'name' }
    ]
})
// works

Playground

Upvotes: 2

doup
doup

Reputation: 911

Something like this could work, although I don't like the explicit list of fields on the generic… it would be more convenient if there was some kind of type-magic for this. ^_^U

interface Config<T extends string> {
    fields: {
        [P in T]: unknown
    };
    table: { id: T }[];
}

const config: Config<'id' | 'title'> = {
    fields: {
        id: {},
        title: {},
    },
    table: [
        { id: 'id' },
        { id: 'name' }, // <== this errors
    ]
};

See in Playground.

Upvotes: 0

Bane2000
Bane2000

Reputation: 187

type fieldsType = {id:any}
const config:{fields:fieldsType, table:{[k:string]:keyof fieldsType}[]} = {
    fields: {
        id: {},
    },
    table: [
        { id: 'id' },
        { id: 'name' },
    ]
};

Upvotes: 0

Related Questions