Можно ли определить типобезопасный дескриптор в TypeScript?

#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. Вы не можете вернуть объект типа, который вы не экспортировали. Вот почему я возвращаю значение как пустой тип интерфейса.
  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. Спасибо! Я надеялся, что может быть решение, которое каким-либо образом не связано с тегированием объекта. Спасибо, что нашли время ответить!