Запретить значения определенного типа в объекте

#typescript

Вопрос:

У меня есть тип SecretString , который может содержать любую конфиденциальную информацию, которую я могу обрабатывать на своем сервере, но из которой я не хочу случайно выходить. Это фирменный строковый тип:

 type SecretString = string amp; {__brand: "secret"}
 

Моя функция ведения журнала принимает строку и объект ( any в настоящее время), который может содержать любую дополнительную информацию, которая может потребоваться. Есть ли у меня способ выразить этот второй параметр как тип, который может быть произвольным объектом, но будет жаловаться, если a SecretString присутствует? Вложенная проверка была бы отличной, но я был бы доволен первым уровнем.

Поскольку SecretString он работает так же, как строка, он обычно исходит из такой функции, как эта:

 function decryptString(encryptedString: EncryptedString): SecretString {
  // ...
}
 

Итак, это пример сценария, в котором я хотел бы получить сообщение об ошибке:

 const keys = decryptString(encryptedKeys);

logger.info('This should not compile!', { 
  valueThatIsOk: 'this is ok', 
  valueThatShouldFail: keys 
});
 

Ответ №1:

Рекурсивно в настоящее время выходит за рамки моего машинописного текста, но на верхнем уровне сопоставленный тип должен работать:

 type SecretString = string amp; {__brand: "secret"};

function log<ObjType>(msg: any, obj: ObjType extends SecretString ? never : ObjType) {
    console.log(msg, obj);
}

let x: SecretString = "example" as SecretString;

log("hi", {example: 42});
log("hi", "more info");
log("hi", x);
//        ^−−−−−−−−−−−−−−− error as desired
 

Ссылка на игровую площадку

Для передачи объекта вместо этого это все то же самое, но в структуре объекта:

 function log<ObjType extends object>(
    msg: any,
    obj: {[key in keyof ObjType]: ObjType[key] extends SecretString ? never : ObjType[key]}
) {
    console.log(msg, obj);
}
 

Ссылка на игровую площадку

(Если вы хотите и то, и другое, вы можете объединить их в союз.)

Комментарии:

1. Я ценю это, но это всего лишь один уровень «сверху» 🙂 Хотя строки и другие примитивные значения разрешены в качестве второго параметра, я всегда передаю объект. Поэтому, когда я сказал, что вложенность не нужна, я имел в виду за пределами этого уровня.

2. @KristianDupont — Я добавил пример, который обрабатывает объект и ваш пример вызова.