Home > Software engineering >  Typescript Advanced Types to Validate Specific Objects
Typescript Advanced Types to Validate Specific Objects

Time:05-22

I'm trying to create a number of types to be able to write:

  1. MyObjectDetails — defines MyObject structure
  2. MyObject - object that correctly follows these MyObjectDetails.
// Details example
const testObjectDetails: MyObjectDetails = {
    name: 'Test',
    fields: [
        {
            name: 'property1'
        },
        {
            name: 'property2'
        }
    ]
}

// Object example
const testObject: MyObject<typeof testObjectDetails> = {
    property1: 123,
    property3: 456 // Should throw Error -> no such field in the details 
    // Should throw Error -> property2 is missing
}

I wrote some code, but they it's not working as expected:

type MyField = string extends infer T ? Readonly<{
  name: T
}> : never

type MyObjectDetails = Readonly<{
  name: string,
  fields: ReadonlyArray<MyField>
}>

type MyObject<T extends MyObjectDetails> = {
    [K in T['fields'][number]['name']]: any;
}

Can you help me?

CodePudding user response:

The problem here is the declaration of testObjectDetails. You are declaring it with the type MyObjectDetails. When you do this, all type information about specific properties is lost because MyObjectDetails does not contain details about specific property names.

One way to solve this would be to use as const and remove the type MyObjectDetails.

const testObjectDetails = {
    name: 'Test',
    fields: [
        {
            name: 'property1'
        },
        {
            name: 'property2'
        }
    ]
} as const

If you still want to have type safety when declaring the testObjectDetails object, you need to use a factory function:

const testObjectDetails = createTestObjectDetails({
    name: 'Test',
    fields: [
        {
            name: 'property1'
        },
        {
            name: 'property2'
        }
    ]
} as const)


function createTestObjectDetails<T extends MyObjectDetails>(testObjDetails: T) : T{
  return testObjDetails
}
  • Related