(code in the end)
I try to write section.full.link
but it gives me such error:
Property 'link' does not exist on type 'SectionSingle | SectionTitle | SectionHeaderMedia'. Property 'link' does not exist on type 'SectionSingle'.ts(2339)
I cant understand what should i do to avoid this error.
Sign ?
afterfull
property or something doesn't help
Code:
export type Section = {
type: "single" | "double" | "title" | "headerMedia";
full?: SectionSingle | SectionTitle | SectionHeaderMedia;
}
export type SectionSingle = {
type: "text" | "media";
content: any;
}
export type SectionTitle = {
title: string;
}
export type SectionHeaderMedia = {
link: string;
alt: string;
}
var section: Section = {
type: "headerMedia",
full: {
link: "/somelink",
alt: "some alt text"
}
}
const cond = section.type === "headerMedia" ? `${section.full.link}` : null
console.log(cond)
CodePudding user response:
You have to create type guard isSectionHeaderMedia
function isSectionHeaderMedia(section: unknown): section is SectionHeaderMedia {
return _.isObject(section) && 'link' in section;
}
_
means lodash here.
isSectionHeaderMedia(section) && section.type === "headerMedia"
?
<div key={index} className="w-full">
<Image
src={section.full.link}
/>
</div>
: null
CodePudding user response:
You can crate a generic
Section that handles all the cases and generates proper full
types.
Then you can create a union type of all the possible sections and then you can use it the way you want.
type HalfSection = {
}
type SectionSingleText = {
}
type SectionSingleMedia = {
}
type SectionTitle = {
title: string;
}
type SectionHeaderMedia = {
link: string;
alt: string;
}
type SectionSingle = {
type: "text" | "media"
content: SectionSingleText | SectionSingleMedia
}
type SectionType = "single" | "double" | "title" | "headerMedia";
type SectionGeneric<ST extends SectionType> = {
type: ST;
full: ST extends "single" ? SectionSingle : ST extends "title" ? SectionTitle : ST extends "headerMedia" ? SectionHeaderMedia : never;
left?: HalfSection;
right?: HalfSection;
}
type Section = SectionGeneric<"single"> | SectionGeneric<"double"> | SectionGeneric<"title"> | SectionGeneric<"headerMedia">
const a: Section = {
type: "headerMedia",
full: {
link: "link",
alt: "alt"
}
};
const fToCall = (section: Section): void => {
section.type === "headerMedia" && console.log(section.full.link)
}
fToCall(a)
Note:
- I had to declare some types to make this work
- You may just as well create a union type from the beginning.
Here's a playground.
You may also want to read up on Discriminated Unions.
CodePudding user response:
You can use a type assertion
const cond = section.type === "headerMedia"
? `${(section.full as SectionHeaderMedia).link}`
: null
or if you want a runtime check, you can transform the SectionHeaderMedia
type into a class, and add one more condition on the if
using the instanceof
operator
export class SectionHeaderMedia {
link = '';
alt = '';
}
section1.type === 'headerMedia' && section1.full instanceof SectionHeaderMedia
? section1.full.link
: null;
CodePudding user response:
It seems like your current definition of Section
is too loose, as it allows a value of a type like {type: "headerMedia", full: SectionSingle}
, where the full
property and the type
property do not agree with each other. So you can't check section.type === "headerMedia"
and conclude that section.full
has a link
property.
If you want to encode this constraint, you should make Section
a discriminated union type, where type
is the discriminant property. Here's one possibility (although I don't know the full extent of your requirements):
export type Section =
{ type: "single", full: SectionSingle } |
{ type: "title", full: SectionTitle } |
{ type: "headerMedia", full: SectionHeaderMedia };
So a Section
is one of those three possibilities. If you check type
and it is "headerMedia"
, then the full
property has to be a SectionHeaderMedia
. And thus your check will succeed as written with no error:
const cond = section.type === "headerMedia" ? `${section.full.link}` : null; // okay