Reputation: 664
Let's say I have the next interface:
interface TestInterface {
id?: string;
type?: string;
}
Is it possible to rewrite in a way that when I perform a check that id !== undefined it'll automatically mean that type property is also defined?
Upvotes: 1
Views: 93
Reputation: 26687
You can mimic this with union types.
Simple example:
interface INonNullable {
id: string;
type: string;
}
interface INullable {
id?: undefined;
type?: undefined;
}
type FinalType = INonNullable | INullable;
function testId(x: FinalType)
{
if (x.id !== undefined) {
x.type // string
}
}
FinalType
is optional, you can simply use (x: INonNullable | INullable)
everywhere.
Add type-guard function:
You can also make function with type guard to test for your criteria and narrow the type that way:
interface INonNullable {
id: string;
type: string;
}
interface INullable {
id?: undefined;
type?: undefined;
}
type FinalType = INonNullable | INullable;
function isNonNullable(x: FinalType): x is INonNullable
{
return x.id !== undefined;
}
let x = {};
if (isNonNullable(x)) {
x.type // string;
}
You have more info about this in Typescript documentation: User-Defined Type Guards
Reusable Empty<T>
:
Another neat option, as mentioned in the comment by Patrick Roberts, to make more re-usable solution using mapped types and generics:
interface INonNullable {
id: string;
type: string;
}
type Empty<T> = {
[K in keyof T]?: undefined;
}
type FinalType<T> = T | Empty<T>;
function testId(x: FinalType<INonNullable>) {
if (x.id !== undefined) {
x.type // string
}
}
Upvotes: 6
Reputation: 1159
Here a way to do what you want, using union :
interface IdWithType {
id: string;
type: string;
}
interface WithoutId {
id?: never;
type?: string;
}
type TestInterface = IdWithType | WithoutId
// You cannot instansiate an object of type TestInterface with an id and with out a type
const yo: TestInterface = { // Type '{ id: string; }' is not assignable to type 'TestInterface'.
id: "hey"
}
const testFunction = (a: TestInterface) => {
if (a.id) {
const b = a.type // string
}
const c = a.type // string | undefined
}
Upvotes: 1
Reputation: 478
Lets see your example:
interface TestInterface {
id?: string;
type?: string;
}
const objectForTest: TestInterface = {
id: '12345',
type: 'some type'
}
You can do it in the following ways:
1) objectForTest?.id
If this operator meet undefined
, it will return this value without throwing a TypeError
.
This is equvalent to:
const testValue = (objectForTest === null || objectForTest === undefined) ?
undefined
:
objectForTest.id;
2) objectForTest!.id
In this case you say to type checker: "Hey, I promise you that objectForTest
is not null
or undefined
".
Upvotes: 1