Home > Enterprise >  Validate property based on another property keys
Validate property based on another property keys

Time:05-25

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:

  • { id: 'id' } is OK, since id key exists in fields
  • { id: 'name' } should error, name key doesn't exist in fields

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

CodePudding user response:

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

CodePudding user response:

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

CodePudding user response:

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.

  • Related