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

Spread syntax into component that uses HTMLAttributes throws a TypeScript error #10780

Open
1 task
mrcsmcln opened this issue Apr 12, 2024 · 4 comments
Open
1 task
Labels
- P3: minor bug An edge case that only affects very specific usage (priority) feat: typescript Related to TypeScript (scope)

Comments

@mrcsmcln
Copy link

Astro Info

Astro                    v4.6.1
Node                     v18.18.0
System                   Linux (x64)
Package Manager          npm
Output                   static
Adapter                  none
Integrations             none

If this issue only occurs in one browser, which browser is a problem?

All browsers

Describe the Bug

Using the spread syntax on a component with a type that uses HTMLAttributes throws a TypeScript error.

For example, consider the following component, MyLink.astro:

---
import type { HTMLAttributes } from 'astro/types'

type Props = { text?: string } & HTMLAttributes<'a'>

const { text, ...props } = Astro.props
---

<a {...props}>
  <slot set:text={text} />
</a>

Next, we'll consume that component in another component, MyComponent.astro:

---
import type { ComponentProps } from 'astro/types'
import MyLink from './MyLink.astro'

type Props = {
  links: ComponentProps<typeof MyLink>[]
}

const { links } = Astro.props
---

<ul>
  {links.map((link) => <li><MyLink {...link} /></li>)}
</ul>

When you use <MyComponent> in, say, a page file and run astro check, TypeScript throws the following error:

Type '{ text?: string | undefined; 'class:list'?: string | Record<string, boolean> | Record<any, any> | Iterable<string> | Iterable<any> | undefined; ... 198 more ...; onfullscreenerror?: string | ... 1 more ... | undefined; }' is not assignable to type 'IntrinsicAttributes & { text?: string | undefined; } & HTMLAttributes<"a">'.
Type '{ text?: string | undefined; 'class:list'?: string | Record<string, boolean> | Record<any, any> | Iterable<string> | Iterable<any> | undefined; ... 198 more ...; onfullscreenerror?: string | ... 1 more ... | undefined; }' is not assignable to type 'IntrinsicAttributes'.

Removing either the spread syntax or swapping the HTMLAttributes<'a'> in favor of a more explicit type removes the error. My guess is because HTMLAttributes consumes a type that some information is lost and it's tripping up TS. If I could somehow do something like import type { HTMLAnchorAttributes } from 'astro/types' as seen here then that might solve the issue? That being said, I'm new to TypeScript so there could very well be something I'm missing.

If you open the minimal reproducible example link I've provided and run astro check, you'll see the same error.

What's the expected result?

I feel like this shouldn't throw an error. In my project, the data is all flowing through an object that generates components and the spread syntax is invaluable. I'm finding it impossible to create components the also accept a class or similar attributes.

Link to Minimal Reproducible Example

https://stackblitz.com/edit/github-fffdsv-s7i8nl?file=src%2Fpages%2Findex.astro&file=src%2Fcomponents%2FMyComponent.astro&file=src%2Fcomponents%2FMyLink.astro

Participation

  • I am willing to submit a pull request for this issue.
@github-actions github-actions bot added the needs triage Issue needs to be triaged label Apr 12, 2024
@florian-lefebvre
Copy link
Member

I can reproduce this issue (by downloading the stackblitz project locally). I'm not sure what's going on either, maybe @Princesseuh will know more

@Callenowy
Copy link

Callenowy commented Apr 21, 2024

I have the same issue with an Input component in the below example.

---
// atoms/input.astro
import type { HTMLAttributes } from 'astro/types';

export interface Props
  extends Omit<HTMLAttributes<'input'>, 'id' | 'name' | 'class'> {
  id?: string;
  name: string;
}

const { name, id, ...inputProps } = Astro.props;
const componentId = id || name;
---

<input
  id={componentId}
  class="placeholder:text-cello-900/60 w-full rounded-lg border border-cello-300 bg-cello-50 p-4 text-base"
  {...inputProps}
/>
---
// moleculres/labeledInput.astro
import type { ComponentProps } from 'astro/types';

import Input from '../atoms/input.astro';

type InputProps = ComponentProps<typeof Input>;

type Props = InputProps & {
  label: string;
};

const { label, name, id, ...inputProps } = Astro.props;
const componentId = id || name;
---

<label
  for={componentId}
  class="block pb-1 text-xl font-normal leading-8 text-cello-900">{label}</label
>
<Input id={componentId} {...inputProps} />

@Princesseuh
Copy link
Member

The issue here I'm pretty sure is that HTMLAttributes, kinda on purpose, does not include all Astro-specific attributes so it ends up being incompatible with IntrinsicAttributes. I wonder if we can just add the new properties, or if that'd break something else.

@Princesseuh Princesseuh added - P3: minor bug An edge case that only affects very specific usage (priority) feat: typescript Related to TypeScript (scope) and removed needs triage Issue needs to be triaged labels Apr 22, 2024
@ArmandPhilippot
Copy link
Contributor

I have a similar issue with Typescript using astro/tsconfigs/strictest config:

[...] is not assignable to type 'IntrinsicAttributes' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.

If I use astro/tsconfigs/strict instead the error message is the same, only:

[...] is not assignable to type 'IntrinsicAttributes'.

From my experience, the culprit is always slot. So to solve the issue in the reproduction we need to declare the Props with Omit:

type Props = {
  links: Omit<ComponentProps<typeof MyLink>, 'slot'>[]
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
- P3: minor bug An edge case that only affects very specific usage (priority) feat: typescript Related to TypeScript (scope)
Projects
None yet
Development

No branches or pull requests

5 participants