I have a typescript interface:
interface MyInterface {
property1?: string;
property2?: string;
};
type InterfaceKey = keyof MyInterface;
The code below creates an object based on MyInterface
. There is a function called verifyObjectProperty
that allows the user to pass in an InterfaceKey
('property1' or 'property2') as a second parameter.
The function validates that the object has a string value for the given key, so it can no longer be undefined.
// - Create an object based on the interface
const myObject: MyInterface = {
property1: 'a string',
}
const verifyObjectProperty = (
objectToVerify: MyInterface,
properyToVerify: InterfaceKey
): MyInterface => {
// - Make sure object has the desired property
if (objectToVerify[properyToVerify] === undefined) {
objectToVerify[properyToVerify] = 'a new string';
}
// - Return the object
return myObject;
};
I want to make it so the verifyObjectProperty
function returns a typescript interface that shows which string is guaranteed to be there.
const verifiedObject = verifyObjectProperty(myObject, 'property1');
type property1 = typeof verifiedObject['property1']; // string
type property2 = typeof verifiedObject['property2']; // string | undefined
Use ts conditional types and mapped types. These features allow you to create new types based on the properties of existing types.
First, create a helper type that will take a property key and return a new type with that property guaranteed to be a string.
type EnsureString<T, K extends keyof T> = T & { [P in K]: string };
This type takes two parameters: T
is the original type (MyInterface
), and K
is the key of the property you want to check as a string. It returns a new type that is the same as T
, but with the property K
guaranteed to be a string.
Then, modify verifyObjectProperty
to use this helper type.
const verifyObjectProperty = <K extends keyof MyInterface>(
objectToVerify: MyInterface,
propertyToVerify: K
): EnsureString<MyInterface, K> => {
// - Make sure object has the desired property
if (objectToVerify[propertyToVerify] === undefined) {
objectToVerify[propertyToVerify] = 'a new string';
}
// - Return the object
return objectToVerify as EnsureString<MyInterface, K>;
};
After calling verifyObjectProperty
, it will infer that the returned object has a string value for the specified property.
const verifiedObject = verifyObjectProperty(myObject, 'property1');
type property1 = typeof verifiedObject['property1']; // string
type property2 = typeof verifiedObject['property2']; // string | undefined