In a Typescript declaration, how to have one value dependent to the type of another?

Viewed 16

I have the following code:

type ValidationResult = 'OK' | 'MISSING_FIELDS' | 'DUPLICATED_FIELD';

type ValidationResultOkDetails = null;
type ValidationResultMissingFieldsDetails = [string];
type ValidationResultDuplicatedField = string;

type Validation = {
  result: ValidationResult,
  details: any
}

Is there a way in Typescript to tell the compiler that when the field result of Validation is 'OK', details is of type ValidationResultOkDetails, when it is 'MISSING_FIELDS', details should be ValidationResultMissingFieldsDetails and so on?

2 Answers
type Validation = {
  result: 'OK',
  details: ValidationResultOkDetails
} | {
  result: 'MISSING_FIELDS',
  details: ValidationResultMissingFieldsDetails
};

This is a bit messy, but it's the nicest way I know of to solve the problem. Others may know more.

Given that OK has no data, here is how I would do it (with example for usage / checking). The compiler "knows" how to narrow down to whichever type based on the signal value in result.

I've declared the individual types separately, but they could be just done inline with the Validation declaration if desired (keep them separate if you need to refer to any of them explicitly).

type ValidationResult = 'OK' | 'MISSING_FIELDS' | 'DUPLICATED_FIELD';

type ValidationResultOkDetails = null;
type ValidationResultMissingFieldsDetails = [string];
type ValidationResultDuplicatedField = string;

type ValidationOK = {
    result: 'OK',
}

type validationMissing = {
    result: 'MISSING_FIELDS',
    details: ValidationResultMissingFieldsDetails,
}

type validationDuplicated = {
    result: 'DUPLICATED_FIELD',
    details: ValidationResultDuplicatedField,
}

type Validation = ValidationOK | validationMissing | validationDuplicated;

const ok: Validation = {
    result: 'OK',
}

const missing: Validation = {
    result: 'MISSING_FIELDS',
    details: ['x'],
}

const duplicated: Validation = {
    result: 'DUPLICATED_FIELD',
    details: 'hello',
}

function handle(v: Validation) {
    if (v.result === 'OK') {
        // no details
    } else if (v.result === 'MISSING_FIELDS') {
        // [string]
        const m = v.details[0];
    } else if (v.result === 'DUPLICATED_FIELD') {
        // string
        const d = v.details;
    }
}

TypeScript Playground

Related