#typescript
#typescript
Вопрос:
Я хотел бы иметь возможность определить типобезопасный эквивалент ДЕСКРИПТОРА или HWND в TypeScript. Вариант использования — создание экземпляра конкретного типа, который предоставляется пользователю как непрозрачный тип, который используется только в качестве входных данных для других функций API. Что-то вроде следующего:
module foo {
export
class Handle<T> {
}
class Property extends Handle<Property>
{
constructor(public value = 12) { super(); }
}
export interface IProperty { }
export function makeProperty(): Handle<IProperty> {
return new Property();
}
export function getPropertyValue(p: Handle<IProperty>) {
return (<Property>p).value;
}
}
module bar {
var s = foo.makeProperty();
var p = foo.getPropertyValue(12); // this should be a compile error
}
Я столкнулся с 2 проблемами:
- Вы не можете вернуть объект типа, который вы не экспортировали. Вот почему я возвращаю значение как пустой тип интерфейса.
- Любое значение реализует пустой интерфейс или пустой класс. Похоже, это делает невозможным создание типобезопасного непрозрачного дескриптора.
Кто-нибудь делал что-то подобное раньше?
Ответ №1:
Почему это не ошибка
Для
var p = foo.getPropertyValue(12); // this should be a compile error
Это не ошибка компиляции, поскольку TypeScript использует структурную систему типов вместо номинальной системы типов, к которой вы могли бы привыкнуть из C # / JAVA и т. Д.
Это означает, что два типа совместимы, если их члены (структура) совпадают независимо от имени (номинального). Например. следующее в порядке
class Foo{}
var foo:Foo = 123; // okay since number contains everything that a Foo needs (which is nothing)
Но следующее не подходит:
class Foo{
bar:number;
}
var foo:Foo = 123; // Error NOT okay since number doesn't contain member bar
Чтобы сделать это ошибкой компиляции
Просто добавьте какое-нибудь уникальное свойство Handle
, которое не существует для недопустимых типов. Например. Я добавил свойство value:number
ниже, которое вызывает ошибку компиляции, как и ожидалось:
module foo {
export class Handle<T> {
constructor(public value:number){}
}
class Property extends Handle<Property>
{
constructor(public value = 12) { super(value); }
}
export interface IProperty { }
export function makeProperty(): Handle<IProperty> {
return new Property();
}
export function getPropertyValue(p: Handle<IProperty>) {
return (<Property>p).value;
}
}
module bar {
var s = foo.makeProperty();
var p = foo.getPropertyValue(12); // Compile Error
}
Комментарии:
1. Правильно. Мой комментарий мог быть сформулирован по-другому. Я хочу , чтобы эта конструкция (или что-то эффективно похожее) была ошибкой компиляции. По сути, я хотел бы передать пользователю непрозрачный тип, который я могу безопасно вернуть к его конкретному типу, не требуя проверки экземпляра. Если это невозможно, то это невозможно. Но, может быть, кто-то еще нашел умный способ добиться этого с помощью системы типов.
2. @ChrisColbert смотрите Обновленный ответ на
to make it a compile error
3. Спасибо! Я надеялся, что может быть решение, которое каким-либо образом не связано с тегированием объекта. Спасибо, что нашли время ответить!