从typescript中的基类泛型中推断子类属性类型

时间:2017-10-12 19:02:16

标签: typescript



    class A<T>
    {
        some: { [K in keyof T]: (x: T[K]) => T[K] }
    }

    interface IB {
        b: number
    }

    class B<T extends IB> extends A<T>
    {
        constructor()
        {
            super()

            /**
             * Type '{ b: (x: T["b"]) => number; }'
             * is not assignable to type '{ [K in keyof T]: (x: T[K]) => T[K]; }'.
             */
            this.some = {
                b: x => 2*x
            }
        }
    }

    interface IC {
        b: number
        c: boolean
    }

    class C<T extends IC> extends B<T>
    {
        constructor()
        {
            super()
            /**
             * Type '{ b: (x: T["b"]) => number; c: (x: T["c"]) => boolean; }'
             * is not assignable to type '{ [K in keyof T]: (x: T[K]) => T[K]; }'
             */
            this.some = {
                b: x => 4*x,
                c: x => !x
            }
        }
    }

您好。我尝试在基类“A”中设置泛型约束,目的是在派生类中自动推断“某些”属性的类型。不幸的是我无法理解为什么我会像上面提到的那样得到TS错误。从我的观点来看,一切似乎都很好。

谢谢!

1 个答案:

答案 0 :(得分:2)

如果我这样做会怎么样?

const b = new B<{ b: 3, z: string }>();

正如您所看到的,我传递了{ b: 3, z: string }类型,这是可以接受的,因为它扩展了{ b: number }。这意味着b.some.b应该是(x: 3) => 3类型。这也意味着b.some.z应该是(x: string) => string类型。对B的实施是否正确?没有; b.some.b实际上是(x: 3) => number类型,b.some.z未定义。所以编译器警告你是有道理的。

首先,让我们来处理z: string问题。也许在A中,您希望some的属性是可选的,如下所示:

class A<T>
{
  some: {[K in keyof T]?: (x: T[K]) => T[K]}
}

这样,您的BC构造函数就可以初始化some,而无需了解额外的属性。

现在,关于b: 3。如果您想允许某人扩展number,那么您可以使用的唯一安全的是身份功能:

this.some = {};
this.some.b = x => x; // okay

但是,您可能不希望任何人传递number类型的b更具体的内容。b。不幸的是,没有什么好办法可以阻止它。所以,很好,只是文档,用户应该只传递number可以是任何this的类型。在这种情况下,您需要告诉编译器不要担心,声明B<IB>类型为this.some = {}; (this as B<IB>).some.b = x => 2 * x; // okay

C

可以为您的DECLARE @T_Find_Text VARCHAR(1000) = 'Foo' IF OBJECT_ID('tempdb..#T_DBNAME') IS NOT NULL DROP TABLE #T_DBNAME IF OBJECT_ID('tempdb..#T_PROCEDURE') IS NOT NULL DROP TABLE #T_PROCEDURE CREATE TABLE #T_DBNAME ( IDX int IDENTITY(1,1) PRIMARY KEY , DBName VARCHAR(255) ) CREATE TABLE #T_PROCEDURE ( IDX int IDENTITY(1,1) PRIMARY KEY , DBName VARCHAR(255) , Procedure_Name VARCHAR(MAX) , Procedure_Description VARCHAR(MAX) ) INSERT INTO #T_DBNAME (DBName) SELECT name FROM master.dbo.sysdatabases DECLARE @T_C_IDX INT = 0 DECLARE @T_C_DBName VARCHAR(255) DECLARE @T_SQL NVARCHAR(MAX) DECLARE @T_SQL_PARAM NVARCHAR(MAX) SET @T_SQL_PARAM = ' @T_C_DBName VARCHAR(255) , @T_Find_Text VARCHAR(255) ' WHILE EXISTS(SELECT TOP 1 IDX FROM #T_DBNAME WHERE IDX > @T_C_IDX ORDER BY IDX ASC) BEGIN SELECT TOP 1 @T_C_DBName = DBName FROM #T_DBNAME WHERE IDX > @T_C_IDX ORDER BY IDX ASC SET @T_SQL = '' SET @T_SQL = @T_SQL + 'INSERT INTO #T_PROCEDURE(DBName, Procedure_Name, Procedure_Description)' SET @T_SQL = @T_SQL + 'SELECT SPECIFIC_CATALOG, ROUTINE_NAME, ROUTINE_DEFINITION ' SET @T_SQL = @T_SQL + 'FROM ' + @T_C_DBName + '.INFORMATION_SCHEMA.ROUTINES ' SET @T_SQL = @T_SQL + 'WHERE ROUTINE_DEFINITION LIKE ''%''+ @T_Find_Text + ''%'' ' SET @T_SQL = @T_SQL + 'AND ROUTINE_TYPE = ''PROCEDURE'' ' BEGIN TRY EXEC SP_EXECUTESQL @T_SQL, @T_SQL_PARAM, @T_C_DBName, @T_Find_Text END TRY BEGIN CATCH SELECT @T_C_DBName + ' ERROR' END CATCH SET @T_C_IDX = @T_C_IDX + 1 END SELECT IDX, DBName, Procedure_Name FROM #T_PROCEDURE ORDER BY DBName ASC 课程执行类似的修复。希望有所帮助;祝你好运!