Open gismya opened 1 year ago
Looking at something like:
interface ResourceTypeMap {
User: User;
Group: Group;
Resource: Resource;
BaseUser: BaseUser;
}
type AbstractResource = keyof ResourceTypeMap;
export interface Appointment<T extends AbstractResource = AbstractResource> {
context?: Context;
context_id?: string;
readonly id?: string;
resource?: ResourceTypeMap[T];
resource_id?: string;
type?: string;
__entity_type__?: "Appointment";
__permissions?: Record<string, any>;
}
Another way to handle it:
export interface Appointment {
context?: Context;
context_id?: string;
readonly id?: string;
resource?: Resource|User|Group|BaseUser;
resource_id?: string;
type?: string;
__entity_type__?: "Appointment";
__permissions?: Record<string, any>;
}
Another way to handle it:
export interface Appointment { context?: Context; context_id?: string; readonly id?: string; resource?: Resource|User|Group|BaseUser; resource_id?: string; type?: string; __entity_type__?: "Appointment"; __permissions?: Record<string, any>; }
Yeah I'd definitely prefer this. It allows for type discrimination.
Also, is there a way to make __entity_type__
non-optional? Not sure, but I think that actually messes with type discrimination as well.
I don't think the optionality affects type discrimination, but I can make some quick tests on that.
How would the first one break type discrimination? The upside to that approach is the possibility to explicitly add what type of resource will be returned since that's sometimes known.
I think the reason it could break it, is because I am also thinking about it in the context of this: #11
Another way to handle it:
export interface Appointment { context?: Context; context_id?: string; readonly id?: string; resource?: Resource|User|Group|BaseUser; resource_id?: string; type?: string; __entity_type__?: "Appointment"; __permissions?: Record<string, any>; }
At first glance, this is the way I'd prefer. Does it have any downsides?
Another way to handle it:
export interface Appointment { context?: Context; context_id?: string; readonly id?: string; resource?: Resource|User|Group|BaseUser; resource_id?: string; type?: string; __entity_type__?: "Appointment"; __permissions?: Record<string, any>; }
At first glance, this is the way I'd prefer. Does it have any downsides?
Not that I know of.
Alright. Maybe I'll pick this up next time I get bored.
Is it only for Resources, or does it need to be fixed for other types too?
It's for anything that inherits. Another one is I think there are instances of Context
that (most commonly) is TypedContext
There could also be multiple levels of inheritance, for example User
inherits from BaseUser
, which inherits from Resources
Ah. If I am to contribute to this, where can I find this hierarchy?
In the schemas. That's what we're using to build the extends
with when generating the interfaces.
For example
export interface User
extends Omit<BaseUser, "__entity_type__" | "__permissions"> {
[...]
}
export interface BaseUser
extends Omit<Resource, "__entity_type__" | "__permissions"> {
[...]
}
export interface Resource {
[...]
}
The ftrack API is built with an inheritance structure such that a returned type is the specified type or any of the types inheriting from that type.
For example, a
Resource
can be aResource
, aGroup
, aBaseUser
, or aUser
. Currently, the generated types only accept that it returns aResource
and gives errors if you try to check for any properties from the other types. We need to decide what strategy to implement to remedy this.