Как условно установить свойство TypeScript на основе другого вложенного свойства?

Технопарк Нобель
Технопарк Нобель
  • Сообщений: 12
  • Последний визит: 31 марта 2025 в 17:13
Как условно установить свойство TypeScript на основе другого вложенного свойства?

У меня есть следующие типы:
type Settings = {
    enableAdvancedFeature?: boolean;
};
 
type Options = {
    settings?: Settings;
    enforceAdvancedOrder?: boolean;
};

Я хочу сделать enforceAdvancedOrder свойство является логическим значением только тогда, когда settings.enableAdvancedFeature является true.

Если settings.enableAdvancedFeature является false или undefined, затем enforceAdvancedOrder должно быть undefined.

Вот пример желаемого поведения:
const validOption1: Options = {
    settings: { enableAdvancedFeature: true },
    enforceAdvancedOrder: true,
};
 
const validOption2: Options = {
    settings: { enableAdvancedFeature: false },
    enforceAdvancedOrder: undefined, // enforceAdvancedOrder should be undefined
};
 
const invalidOption: Options = {
    settings: { enableAdvancedFeature: false },
    enforceAdvancedOrder: true, // This should cause a TypeScript error
};<code>
Я попытался определить условный тип для параметров, но не смог понять, как обеспечить эту зависимость между вложенными свойствами.
 
Как я могу определить тип Options, чтобы добиться такого поведения, сохраняя при этом его безопасность? Любые предложения будут очень признательны!
Владимир Соколов
Владимир Соколов
  • Сообщений: 31
  • Последний визит: 25 марта 2025 в 21:57
Просто так:
type ConditionalOption =
    | { enforceAdvancedOrder?: boolean, settings?: { enableAdvancedFeature?: true } }
    | { enforceAdvancedOrder?: undefined, settings?: { enableAdvancedFeature?: false | undefined } }

Примеры:
let a: ConditionalOption = {
    settings: {
        enableAdvancedFeature: true
    },
    enforceAdvancedOrder: true
} // okay
 
let b: ConditionalOption = {
    settings: {
        enableAdvancedFeature: false
    },
    enforceAdvancedOrder: true
} // throws error
 
let c: ConditionalOption = {
    settings: {
        enableAdvancedFeature: false
    },
    enforceAdvancedOrder: undefined
} // okay
Автотрейд
Автотрейд
  • Сообщений: 18
  • Последний визит: 24 февраля 2025 в 11:27
Вы можете использовать тип объединения, который позволяет enforceAdvancedOrder быть логическим значением, если enableAdvancedFeatures установлено на true и в противном случае требует, чтобы enforceAdvancedOrder является неопределенным.

Вот как:
type Options = ({
    settings?: Settings<true>;
    enforceAdvancedOrder?: boolean;
} | {
    settings?: Settings<false | undefined>;
    enforceAdvancedOrder?: never;
});
 
type Settings<B extends boolean | undefined = boolean> = B extends undefined ? {
    enableAdvancedFeature?: B;
} : {
    enableAdvancedFeature: B;
};

Вот несколько образцов для проверки:
const validOption1: Options = {
    settings: { enableAdvancedFeature: true },
    enforceAdvancedOrder: true,
};
 
const validOption2: Options = {
    settings: { enableAdvancedFeature: false },
    enforceAdvancedOrder: undefined, // enforceAdvancedOrder should be undefined
};
 
const validOption3: Options = {
    settings: {},
    enforceAdvancedOrder: undefined, // enforceAdvancedOrder should be undefined
};
 
const invalidOption: Options = {
    settings: { enableAdvancedFeature: false },
    enforceAdvancedOrder: true, // This should cause a TypeScript error
};
 
const invalidOption2: Options = {
    settings: {},
    enforceAdvancedOrder: true, // This should cause a TypeScript error
};
Авторизуйтесь, чтобы писать на форуме.