I used Typescript tagged unions in order to type check what interface the argument of a function uses. Here are two interfaces that can each be passed into the func function below
export interface IPubArticle {
kind: "IPubArticle"
node: {
fields: {
slug: string
}
frontmatter: {
title: string
category: string
author: string
issue: string
date: string
givenRank: number
}
}
}
export interface IArticleSquare{
kind: "IArticleSquare"
node: {
fields: {
slug: string
}
frontmatter: {
title: string
subTitle: string
category: string
author: string
featuredImage: {
childImageSharp: IFluidObject
}
date: string
givenRank: number
}
}
}
const func = ({data}: {data: IArticleSquare | IPubArticle}) => {
switch (data.kind){
case "IArticleSquare":
...
case "IPubArticle":
...
}
}
I am getting a problem now because apparently my graphql call doesn't match the interface because the variable kind is missing
Argument of type '{ node: { fields: { slug: string; }; frontmatter: { title: string; subTitle: string; date: string; description: string; category: string; author: string; givenRank: number; featuredImage: { childImageSharp: GatsbyImageProps; }; }; }; }[]' is not assignable to parameter of type 'IArticleSquare[]'.
Property 'kind' is missing in type '{ node: { fields: { slug: string; }; frontmatter: { title: string; subTitle: string; date: string; description: string; category: string; author: string; givenRank: number; featuredImage: { childImageSharp: GatsbyImageProps; }; }; }; }' but required in type 'IArticleSquare'.ts(2345)
article.interface.ts(21, 3): 'kind' is declared here.
And here is my graphql query
export const pageQuery = graphql`
query($path: string!) {
allMarkdownRemark(
sort: { order: DESC, fields: [frontmatter___date] }
) {
edges {
node {
fields {
slug
}
frontmatter {
title
subTitle
date(formatstring: "MMMM DD, YYYY")
category
featuredImage {
childImageSharp {
fluid(maxWidth: 400) {
...GatsbyImageSharpFluid
}
}
}
}
}
}
}
How can I fix this? I really have no idea what to do
Assuming that IArticleSquareNode
always has a subtitle
in frontmatter
and IArticleNode
does not, you can write a User-Defined Type Guard (isSquareNode
) to help you identify the node type.
interface IFrontmatter {
title: string
category: string
author: string
issue: string
date: string
givenRank: number
}
interface IFrontmatterSquare extends IFrontmatter {
subTitle: string
}
interface IFields {
slug: string
}
interface IArticleNode {
fields: IFields
frontmatter: IFrontmatter
}
interface IArticleSquareNode {
fields: IFields
frontmatter: IFrontmatterSquare
}
function isSquareNode(
node: IArticleSquareNode | IArticleNode,
): node is IArticleSquareNode {
return (node as IArticleSquareNode).frontmatter.subTitle !== undefined
}
const func = (node: IArticleSquareNode | IArticleNode) => {
if (isSquareNode(node)) {
return 'is of type IArticleSquareNode'
} else {
return 'is of type IArticleNode'
}
}
const testArticleNode = {
fields: {
slug: '/myslug/',
},
frontmatter: {
title: 'title',
category: 'category',
author: 'author',
issue: 'issue',
date: 'date',
givenRank: 1,
},
}
const testArticleSquareNode = {
fields: {
slug: '/myslug/',
},
frontmatter: {
title: 'title',
subTitle: 'subTitle',
category: 'category',
author: 'author',
issue: 'issue',
date: 'date',
givenRank: 1,
},
}
console.log(func(testArticleNode)) // is of type IArticleNode
console.log(func(testArticleSquareNode)) // is of type IArticleSquareNode