Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How do I use one layout for .md, .mdx, and .astro files with TypeScript? #8692

Closed
AleksandrHovhannisyan opened this issue Jun 26, 2024 · 4 comments · Fixed by #8763
Closed
Labels
improve documentation Enhance existing documentation (e.g. add an example, improve description)

Comments

@AleksandrHovhannisyan
Copy link

📚 Subject area/topic

Using one Layout for .md, .mdx, and .astro

📋 Page(s) affected (or suggested, for new content)

https://docs.astro.build/en/basics/layouts/#using-one-layout-for-md-mdx-and-astro

📋 Description of content that is out-of-date or incorrect

The article linked above gives the following example of an Astro layout file that accepts both JSX props and frontmatter props:

---
const { title } = Astro.props.frontmatter || Astro.props;
---
<html>
  <head></head>
  <body>
    <h1>{title}</h1>
    <slot />
  </body>
</html>

But it's unclear how this can be used together with TypeScript to get typesafety.

If I just do this, then TypeScript complains that frontmatter does not exist on Astro.props:

---
type Props = { title: string };
const { title } = Astro.props.frontmatter || Astro.props;
---
<html>
  <head></head>
  <body>
    <h1>{title}</h1>
    <slot />
  </body>
</html>
Property 'frontmatter' does not exist on type 'Props'.

So then I tried this, but that doesn't work either:

---
import type { MarkdownLayoutProps } from 'astro';

type LayoutProps = {
  title: string;
}

type Props = MarkdownLayoutProps<LayoutProps> | LayoutProps;

const { title } = Astro.props.frontmatter || Astro.props;
---
<html>
  <head></head>
  <body>
    <h1>{title}</h1>
    <slot />
  </body>
</html>

TypeScript still complains that Astro.props.frontmatter does not exist:

Property 'frontmatter' does not exist on type 'Props'.
  Property 'frontmatter' does not exist on type 'LayoutProps'.ts(2339)

Finally, I also tried:

---
import type { MarkdownLayoutProps } from 'astro';
type Props = MarkdownLayoutProps<{ title: string }>;
const { title } = Astro.props.frontmatter || Astro.props;
---
<html>
  <head></head>
  <body>
    <h1>{title}</h1>
    <slot />
  </body>
</html>

But then the JSX usage gives a different error:

src/pages/index.astro

---
import BaseLayout from '../layouts/BaseLayout.astro'
---

<BaseLayout title="Home page!">
    <p>test</p>
</BaseLayout>
Type '{ children: any; title: string; }' is not assignable to type 'IntrinsicAttributes & Props'.
  Property 'title' does not exist on type 'IntrinsicAttributes & Props'.

🖥️ Reproduction in StackBlitz (if reporting incorrect content or code samples)

No response

@AleksandrHovhannisyan AleksandrHovhannisyan added the improve documentation Enhance existing documentation (e.g. add an example, improve description) label Jun 26, 2024
@at-the-vr
Copy link
Member

As a workaround I prefer a layout similar to https://github.com/ElianCodes/brutal/blob/34a13ed9ee02e41a5eafc764f6c6b606a9b99855/src/layouts/Default.astro for OP's concern. Gonna look into this to find what could be missing with respect to Docs later today

@at-the-vr
Copy link
Member

When dealing with Astro.props.frontmatter, default Props can't be overridden, I can't find the documentation for that specifically (maybe a docs PR needed? question to Sarah). A custom prop interface is required in that case:

---
type CustomProps = { title: string };
const { title }: CustomProps = Astro.props.frontmatter || Astro.props;
---
<html>
  <head></head>
  <body>
    <h1>{title}</h1>
    <slot />
  </body>
</html>

Linking a gist for consecutive code snippets shared in this issue - Docs Issue 8692.

@sarah11918
Copy link
Member

Thanks for this @at-the-vr ! Since the HTML template part is the same in both examples, I'm wondering whether we can get away with showing just the script part here as the version to use if you're writing TypeScript?

As for the default Props types can't be overridden, maybe there's a place in the TypeScript guide itself to mention that?

@at-the-vr
Copy link
Member

Sure I will look into typescript.mdx to address this one 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
improve documentation Enhance existing documentation (e.g. add an example, improve description)
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants