I have a value that's either {}
, or an object with 30 fields. ESLint suggests that a reasonable type for the former case is Record<string, never>
, so the compound type looks like Record<string, never> | MyBigObjectType
.
I'm trying to discriminate between the two cases using the presence or absence of a field Foo
. Unfortunately, I can't use "Foo" in val
or !!val.Foo
because the type checker supposes that it could be present in Record<string, never>
. But it can't! That's the whole purpose of never
!
How do I accomplish this without type casts?
CodePudding user response:
If you use Record<never, never>
as the empty object type then you can use "Foo" in val
to discriminate.
CodePudding user response:
You haven't shared how you're creating or using these objects, but if using an assertion (cast) is specifically the problem, you can use a function returning a type predicate for compile-time and runtime safety.
// "an object with 30 fields"
type MyBigObjectType = {
foo: string;
bar: number;
// etc...
};
function isMyObject (value: object): value is MyBigObjectType {
// checking specified size of keys and presence of 'foo' property,
// but you can modify to fit your requirements
return Object.keys(value).length === 30 && 'foo' in value;
}
function fn (value: MyBigObjectType): void {}
const o1 = {};
fn(o1); // nope
if (isMyObject(o1)) fn(o1); // ok
declare const o2: object;
fn(o2); // nope
if (isMyObject(o2)) fn(o2); // ok
declare const o3: MyBigObjectType;
fn(o3); // ok