You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
There is a base element type (e.g. ContentTypeElements.IElementShared) and a set of specific element types (e.g. ContentTypeElements.IAssetElement) that extend from the base type.
In places where there can be any of the specific elements (e.g. in the builder when upserting a content type or in the elements property when a content type is loaded from MAPI), the type of all the elements is the base type. This means that when I want to perform logic on a specific subset of element types, I have to manually assert the type (as MySpecificType).
Example:
constrenderElement=(element: ContentTypeElements.IElementShared)=>{switch(element.type){case"asset": {consttypedElement=elementasContentTypeElements.IAssetElement;// here I can work with the typedElement as an asset element// but nothing prevents me from doing "as ContentTypeElements.IDateTimeElement" instead so its easy to make a mistake}// ... similarly for other element types}};
It is not only pretty tedious to write all the as assertions, but it also exposes us to mistakes asserting a different type than what is expected based on the value in the type property. TypeScript cannot help us here because of the structure of the element types in the SDK. Since the specific element types and the base type have no link between them (the interface extends doesn't create a link between those two, it just adds all the properties from the base into the specific element) TypeScript has no way of knowing what type is associated with different values of the type property.
Proposed solution
Fortunately, we can change the structure of the element types so that TypeScript can infer the proper type of the element based on the type property. We can leverage a discriminated union type for this. As a union type, the generic element would look something like this:
exporttypeElement=// IElementShared doesn't make much sense as a name, because it is not about sharing propertiesIAssetElement|IDateTimeElement|INumberElement// ... rest of the elements// we can still have a base element to share properties and avoid writing them in all the elements// but now it doesn't make sense to export it, because it is not something users would need to use, its just for internal reusabilityinterfaceIAssetElementextendsBaseElement{type: "asset";// ...}typeBaseElement={// ...};
With the type written like this, we don't need to manually assert the element type, because TypeScript is able to infer it so we are safe from this type of mistakes.
Example:
constrenderElement=(element: ContentTypeElements.Element)=>{switch(element.type){case"asset": {// here the parameter "element" is already typed as ContentTypeElement.IAssetElement, because TypeScript knows that// when "element.type === "asset" then the type of element must be IAssetElement}}};
The same also applies to APIs where the user has to supply a value of type ContentTypeElements.Element. When the user specifies the type property, TypeScript (and IntelliSense) will know the rest of the properties that need to be specified and their type. Because of that, there would be no need for the element builders.
//....withData({elements: [{type: "asset",// here I get IntelliSense suggestions for all the properties and their types},],});
This improvement applies to all element types except for the variant elements because, in the language variant, there is no type property that could determine the type of the element.
The text was updated successfully, but these errors were encountered:
@Nickm615 can you please have another look? Perhaps try the example that @JiriLojda provided in the description to see if the types match the desired outcome.
Motivation
There is a base element type (e.g.
ContentTypeElements.IElementShared
) and a set of specific element types (e.g.ContentTypeElements.IAssetElement
) that extend from the base type.In places where there can be any of the specific elements (e.g. in the builder when upserting a content type or in the
elements
property when a content type is loaded from MAPI), the type of all the elements is the base type. This means that when I want to perform logic on a specific subset of element types, I have to manually assert the type (as MySpecificType
).Example:
It is not only pretty tedious to write all the
as
assertions, but it also exposes us to mistakes asserting a different type than what is expected based on the value in thetype
property. TypeScript cannot help us here because of the structure of the element types in the SDK. Since the specific element types and the base type have no link between them (the interfaceextends
doesn't create a link between those two, it just adds all the properties from the base into the specific element) TypeScript has no way of knowing what type is associated with different values of thetype
property.Proposed solution
Fortunately, we can change the structure of the element types so that TypeScript can infer the proper type of the element based on the
type
property. We can leverage a discriminated union type for this. As a union type, the generic element would look something like this:With the type written like this, we don't need to manually assert the element type, because TypeScript is able to infer it so we are safe from this type of mistakes.
Example:
The same also applies to APIs where the user has to supply a value of type
ContentTypeElements.Element
. When the user specifies thetype
property, TypeScript (and IntelliSense) will know the rest of the properties that need to be specified and their type. Because of that, there would be no need for the element builders.This improvement applies to all element types except for the variant elements because, in the language variant, there is no
type
property that could determine the type of the element.The text was updated successfully, but these errors were encountered: