I have a type SecretString
which can contain any kind of sensitive information that I may handle on my server but which I don't want to accidentally log out. It's a branded string type:
type SecretString = string & {__brand: "secret"}
My logging function takes a string and an object (any
, currently) which can contain whatever additional information might be necessary. Is there a way for me to express that second parameter as a type that can be an arbitrary object but will complain if a SecretString
is present? Nested checking would be great but I would be happy with first level.
As the SecretString
works just like a string, it typically comes from a function like this one:
function decryptString(encryptedString: EncryptedString): SecretString {
// ...
}
So this is an example of a scenario where I would like an error message:
const keys = decryptString(encryptedKeys);
logger.info('This should not compile!', {
valueThatIsOk: 'this is ok',
valueThatShouldFail: keys
});
CodePudding user response:
Recursively is beyond my TypeScript at present, but at the top level a mapped type should work:
type SecretString = string & {__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
For passing an object instead, it's still the same thing but in an object structure:
function log<ObjType extends object>(
msg: any,
obj: {[key in keyof ObjType]: ObjType[key] extends SecretString ? never : ObjType[key]}
) {
console.log(msg, obj);
}
(If you want both, you can combine them in a union.)