There are TONS of questions about conditional types based on a value. However I'm not sure can scenario below be implemented at all.
I'm getting acquainted with conditional types and I'm wondering if it's possible to make a conditional type that will be dependant on a non-empty string.
Let's consider next interface:
interface Animal {
dogName: string;
canBark: boolean;
}
and
interface AnimalToBeMapped {
dogsNickname?: string;
/// some other props
}
I'm using this interface to map an object
function mapAnimal(animal: AnimalToBeMapped): Animal {
return {
dogName: animal.dogsNickname,
canBark: !animal.dogsNickname
}
}
I'm setting canBark
property to true
only when the argument object has a dogName
property set (should work also for empty string vs. non-empty string).
What I want to do is to add additional type-safety to my Animal
interface (if someone is setting dogName
manually to be defined then I want to force canBark
property to be true
and vise versa).
example:
const exmpl1: Animal = {
dogName: 'Rex',
canBark: false // I want an error here
}
and
const exmpl2: Animal = {
dogName: '',
canBark: true // An error here
}
Please let me know if it works for you
type NonEmptyString<T extends string> = T extends '' ? never : T;
type WithName = {
dogName: string,
canBark: true,
}
type WithoutName = {
dogName?: '',
canBark: false
};
type Animal = WithName | WithoutName;
type Overloadings =
& ((arg: { canBark: false }) => Animal)
& ((arg: { dogName: '', canBark: false }) => Animal)
& (<S extends string>(arg: { dogName: NonEmptyString<S>, canBark: true }) => Animal)
const animal: Overloadings = (arg: Animal) => {
return arg
}
const x = animal({ dogName: '', canBark: false }) // ok
const xx = animal({ dogName: 'a', canBark: true }) // ok
const xxx = animal({ dogName: 'a', canBark: false }) // error
const xxxx = animal({ dogName: '', canBark: true }) // error
const xxxxx = animal({ canBark: true }) // error
const xxxxxx = animal({ canBark: false }) // ok
Playground
It is not so easy for TS to find distinguish between empty string and string. Type string
is assignable to literal type ''
(empty string), that's whu I used NonEmptyString
helper
UPDATE If you are interested in a bit simplier solution, which is not requires extra funxtion, see this example:
type WithName = {
dogName: string,
canBark: true,
}
type WithoutName = {
canBark: false
};
type Animal = WithName | WithoutName;
const x: Animal = {
dogName: 'name',
canBark: true
}; // ok
const xx:Animal={
canBark:false
}; // ok
const xxx:Animal={
canBark:true
} // expected error
const xxxx:Animal={
dogName:''
} // expected error
Playground
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With