Слияние объявлений не работает для интерфейсов

Я пытаюсь добавить настраиваемое поле в Stripe.Subscription с помощью https://www.typescriptlang.org/docs/handbook/declaration-merging.html, но это не работает.

import Stripe from 'stripe';

export {};

// Looks like this mwrhod also doesn't work.
// declare global {
//     interface Subscription {
//         role: string;
//     }
// }

// This might also be the wrong way to declare it as it's not using the imported Stripe namespace as all.
declare global {
    // eslint-disable-next-line @typescript-eslint/no-namespace
    namespace Stripe {
        interface Subscription {
            role: string;
        }
    }
}

Stripe.Subscription.prototype.role: string = this['role']; // <= Error: TS2339: Property 'Subscription' does not exist on type 'typeof import("stripe")'.

Затем, если я попытаюсь получить доступ к role:

const subscription: Stripe.Subscription = getSubscription();
subscription.role; // <= TS2339: Property 'role' does not exist on type 'Subscription'.

Вот Subscription объявление интерфейса https://github.com/stripe/stripe-node/blob/547d9d34d07f3dbcee131fb0a00368b09ed37741/types/Subscriptions.d.ts#L10

Вы говорите, что объявление «не работает для интерфейсов», но здесь оно работает отлично. Когда вы пишете Stripe.Subscription, вы, очевидно, ожидаете, что будет значение конструктора класса с именем Subscription, экспортируемое полосой, а его нет. Интерфейсы — это типы, а конструкторы классов — это значения, и только потому, что у вас есть именованный интерфейс, это не означает, что также существует именованное значение, которое создает экземпляры этого интерфейса. Такие вещи случаются с объявлениями class, но я не вижу class нигде в вашем коде.

jcalz 22.01.2023 19:30

... В любом случае, вы можете отредактировать вопрос, чтобы заголовок более точно описывал вашу проблему, которая, по-видимому, специфична для полосы, чтобы у вас было больше шансов правильно взглянуть на вопрос. Прямо сейчас это своего рода XY-проблема; ваша основная проблема заключается в добавлении настраиваемого свойства к подпискам в полосе (если я правильно сформулировал это, я понятия не имею, что такое полоса, на самом деле), и вы думали, что слияние объявлений позволит вам это сделать; вместо того, чтобы спрашивать о неудачной попытке, просто спросите о своей основной проблеме. Удачи!

jcalz 22.01.2023 19:34
Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой Zod и раскрыть некоторые ее особенности, например, возможности валидации и трансформации данных, а также...
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Мне нравится библиотека Mantine Component , но заставить ее работать без проблем с Remix бывает непросто.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
TypeScript против JavaScript
TypeScript против JavaScript
TypeScript vs JavaScript - в чем различия и какой из них выбрать?
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Не все нужно хранить на стороне сервера. Иногда все, что вам нужно, это постоянное хранилище на стороне клиента для хранения уникальных для клиента...
Что такое ленивая загрузка в Angular и как ее применять
Что такое ленивая загрузка в Angular и как ее применять
Ленивая загрузка - это техника, используемая в Angular для повышения производительности приложения путем загрузки модулей только тогда, когда они...
1
2
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Просто убедитесь, что вы следуете тому же шаблону объявления, что и исходная библиотека:

declare module 'stripe' {
    namespace Stripe {
        interface Subscription {
            /** Attached JSDoc */
            role: string;
        }
    }
}

declare const subscription: Stripe.Subscription;
subscription.role; // Okay
//           ^? string

Ссылка на игровую площадку

Как насчет значения role, как его определить? Stripe.Subscription.prototype по-прежнему выдает ту же ошибку: TS2339: свойство «Подписка» не существует для типа «typeof Stripe».

vovahost 22.01.2023 10:11

Я не уверен, что понимаю, что вы пытаетесь там сделать? Вы хотите определить значение по умолчанию? Если да, то это звучит как другой вопрос, так как это зависит от того, как Stripe создает подписку.

ghybs 22.01.2023 10:21

Интерфейс Subscription отображает ответ json от Stripe API. Объект json имеет дополнительный ключ role, которого нет в интерфейсе Subscription. Я хочу безопасно расширить интерфейс Subscription, чтобы определить это дополнительное поле.

vovahost 22.01.2023 11:19

Вот что я понимаю из вашего описания: ответ Stripe API — это Subscription, за исключением того, что во время выполнения вы видите дополнительный ключ role, который не объявлен в интерфейсе, но который вы хотите использовать (читать и/или писать). И ТС предупреждает, что тип промахивается. В этом случае приведенный выше ответ уже охватывает ваш вариант использования. Если вы хотите написать в этот ключ, вы можете просто сделать это: tsplay.dev/mZQ2EN Я до сих пор не понимаю, чего вы пытаетесь добиться с помощью Stripe.Subscription.prototype извините.

ghybs 22.01.2023 13:47

Что это за поле role, и если оно является частью JSON-ответа Stripe API, почему оно еще не содержится в официальных определениях Stripe Typescript?

karllekko 23.01.2023 10:23

Я включил упрощенный вариант использования, но свойство role является вложенным. В любом случае решения @ghybs работают отлично. Вся путаница была связана с другими решениями, которые я нашел на Stackoverflow, которые также устанавливали поле для прототипа. Теперь я понимаю, что это относится только к классам.

vovahost 25.01.2023 07:20

Другие вопросы по теме