はじめに
通常でもpropsに型を指定して、記述できる内容を制限していますが、
状況により、制限する内容を変えたい場合、ジェネリクスで指定できれば見た目にも分かりやすくなります
今回作るもの
今回の要件として、リンクのコンポーネントを用意します
リンクの型を作成
// 基本
interface BaseLinkType {
  path: `https://${string}` | `/${string}`
  text: string
}
// IR
export interface Ir extends BaseLinkType {
  path: `/ir/${string}`
}
// お知らせ
export interface Information extends BaseLinkType {
  path: `/info/${string}`;
  text: `お知らせ:${string}`
}
// サービスサイト
export interface Service extends BaseLinkType {
  path: `https://www.xxxx.co.jp/${string}`
}
コンポーネントにジェネリクスの型を適用する
import React, { PropsWithChildren } from 'react';
type Link = Ir | Information | Service
interface Props<T extends Link> {
  path: T['path']
  text: T['text']
}
export const Link = <T extends Link>({
  path,
  text
}: PropsWithChildren<Props<T>>): React.ReactElement => {
  return (
    <a href={path}>{text}&l;/a>
  )
}
Linkコンポーネントを利用する側の実装例です
import React from 'react'
import { Link, type Information } from './Link'
export const Test: React.FC = () => {
  return (
    <Link<Information>
      path="/info/20230412"
      text="お知らせ:XX店オープン"
    />
  )
}
リファクタリング
ジェネリクスの指定を、文字列にした方が、型を export / import しなくてよくなりますtype Link = {
  ir: Ir
  info: Information
  service: Service
}
interface Props<T extends keyof Link> {
  path: Link[T]['path']
  text: Link[T]['text']
}
export const Link = <T extends keyof Link>({
  path,
  text
}: PropsWithChildren<Props<T>>): React.ReactElement => {
  return (
    <a href={path}>{text}</a>
  )
}
import React from 'react'
import { Link } from './Link'
export const Test: React.FC = () => {
  return (
    <Link<'info'>
      path="/info/20230412"
      text="お知らせ:XX店オープン"
    />
  )
}
リファクタリング後のコンポーネント全体のコード
import React, { PropsWithChildren } from 'react';
// 基本
interface BaseLinkType {
  path: `https://${string}` | `/${string}`;
  text: string;
}
// IR
interface Ir extends BaseLinkType {
  path: `/ir/${string}`;
}
// お知らせ
interface Information extends BaseLinkType {
  path: `/info/${string}`;
  text: `お知らせ:${string}`
}
// サービスサイト
interface Service extends BaseLinkType {
  path: `https://www.xxxx.co.jp/${string}`;
}
type Link = {
  ir: Ir
  info: Information
  service: Service
}
interface Props<T extends keyof Link> {
  path: Link[T]['path']
  text: Link[T]['text']
}
export const Link = <T extends keyof Link>({
  path,
  text
}: PropsWithChildren<Props<T>>): React.ReactElement => {
  return (
    <a href={path}>{text}</a>
  )
}