typescript - Svelte starkt typade klass av komponenter


Jag arbetar på ett komponentbibliotek som har en liten twist på hur komponenter grupperas. Jag grupperar komponenter i klasser för att göra användandet av biblioteket enklare för slutanvändare. Istället för att komma ihåg vilka namngivna slots som är tillgängliga skulle de istället komma åt de anpassade slots med hjälp av punktnotation. Till exempel kan en Card-komponent ha en Header, Body och en Footer. I mitt bibliotek skulle jag vilja använda dessa komponenter på följande sätt:

<Card>
  <Card.Header>I am a Header</Card.Header>
  <Card.Body>I am a Body</Card.Body>
  <Card.Footer>I am a Footer</Card.Footer>
</Card>

Jag har detta fungerande för närvarande, men jag försöker få det starkt typat också och det är där jag stöter på problem. Här är min filstruktur:

card
  | Card.svelte
  | Body.svelte
  | Header.svelte
  | Footer.svelte
  | index.ts

Min index.ts-fil har följande kod:

import OriginalCard from './Card.svelte';
import Header from './Header.svelte';
import Footer from './Footer.svelte';
import Body from './Body.svelte';

const Card = OriginalCard;
Card.Header = Header;
Card.Body = Body;
Card.Footer = Footer;

export default Card;

Header, Body och Footer returnerar alla följande fel: Property 'Header' does not exist on type 'typeof default'. ts(2339)

När man använder komponenten på detta sätt:

<script lang="ts>
  import Card from '@components/card';
</script>

<Card>
  <Card.Header>I am a Header</Card.Header>
  <Card.Body>I am a Body</Card.Body>
  <Card.Footer>I am a Footer</Card.Footer>
</Card>

Header, Body och Footer returnerar alla följande fel: Property 'Body' does not exist on type 'typeof Card__SvelteComponent_'. ts(2339)

Hur åtgärdar jag dessa fel?

REDIGERA

Efter att ha installerat detta paket i ett annat projekt märkte jag två problem som det accepterade svaret inte löser:

1). <Card /> ger följande ts-fel - Förväntade 0 argument, men fick 1. och bryter all intellisense för tillåtna egenskaper.

2). Intellisense fungerar inte med punktnotationen. När jag skriver <Card. får jag inga förslag för några av underkomponenterna och istället visar den bara alla komponenter i hela paketet.

Det önskade resultatet är att inte ha ts-felen och inte förlora intellisense med paketet.

Jag försökte också att utvidga CardStatic på följande sätt: interface CardStatic extends OriginalCard och samma problem fortsatte att kvarstå.

Svar #1

Du måste utöka den kända typen för att lägga till de ytterligare egenskaperna. Eftersom de är statiska skulle jag prova något liknande detta:

const Card = OriginalCard as CardStatic;
Card.Header = Header;
Card.Body = Body;
Card.Footer = Footer;

export default Card;

export interface CardStatic {
    new(...args: ConstructorParameters<typeof OriginalCard>): OriginalCard;
    Header: typeof Header;
    Body: typeof Body;
    Footer: typeof Footer;
}

Svar #2

Jag hittade ett enklare sätt att göra detta i SvelteKit när det används för att skapa komponentbibliotek: Exportera ett objekt som heter Card från lib-mappens index.ts-fil på detta sätt:

import _Card from "./Card.svelte";
import _CardBody from "./CardBody.svelte";
import _CardHeader from "./CardHeader.svelte";
import _CardFooter from "./CardFooter.svelte";

export const Card = {
    Root: _Card,
    Footer: _CardFooter,
    Header: _CardHeader,
    Body: _CardBody
};

Med detta behöver du inga ytterligare typningar, men det finns en hake: <Card>-komponenten är nu <Card.Root>. Den skulle importeras och användas från andra projekt på detta sätt:

<script lang="ts">
    import { Card } from 'the-component-library';
</script>

<Card.Root>
    <Card.Header>My Header</Card.Header>
    <Card.Footer>My Footer</Card.Footer>
</Card.Root>

På grund av fångsten skulle jag säga att detta inte kan anses vara ett svar, men jag ställer mig ändå frivillig om denna fångst är en liten sak för människor jämfört med att gå igenom skrivdelen som tillhandahålls av det accepterade svaret.