当我拥有一个最初以null开头的属性时,如何将其作为参数传递给期望非null值的匿名回调函数,而不会抱怨打字稿?
我可以将函数调用包装在if语句中以检查是否为null,这样可以在函数调用级别停止键入脚本的抱怨,但是在回调中,键入脚本仍然会抱怨。
这是代码段。我允许某些DatabaseState
属性为null,因为这是它们的初始化方式。
//types.ts
export interface DatabaseState {
db: PouchDB.Database | null;
remoteDb: PouchDB.Database | null;
dbReplication: PouchDB.Replication.Sync<{}> | null;
dbSyncStatus: number;
dbSyncInfo: string;
dbSyncError: string;
}
//state typing - state: DatabaseState
//An action in database.ts
async startDatabaseSyncronisation({ state, commit, dispatch }) {
var opts = { live: true, retry: true };
if (state.remoteDb != null && state.db != null) {
/* THE IF STATEMENT PREVENTS THE BELOW FUNCTION FROM CAUSING TYPESCRIPT TO COMPLAIN */
await PouchDB.replicate(state.remoteDb, state.db, opts).on("complete",
function(info) {
/* WITHIN THE CALLBACK FUNCTION THOUGH, TYPESCRIPT COMPLAINS THAT state.remoteDb and state.db
COULD BE NULL AND THE FUNCTION DOESN'T ACCEPT A NULL VALUE */
let replication = PouchDB.sync(state.remoteDb, state.db, opts)
.on("paused", function(err: {}) {
dispatch("onSyncPaused", err);
})
.on("active", function() {
dispatch("onSyncActive");
})
.on("denied", function(err: {}) {
dispatch("onSyncError", err);
})
.on("error", function(err: {}) {
dispatch("onSyncError", err);
})
.on("complete", function() {});
commit(SET_DB_REPLICATION, replication);
}
);
}
},
我应该如何进行这类类型的检查? 是否有一种更加“ Typescript友好”的方式将初始值描述为未设置?
该项目使用Vue和Vuex进行状态管理。
答案 0 :(得分:0)
状态的值可以在if check和complate
回调之间改变。如果您确定状态没有改变,可以使用null assertion operator:state!.remoteDb
告诉编译器认为这些值不能为空。
答案 1 :(得分:0)
我强烈建议您始终使用null
帐户。 null
的概念被认为是一个错误,并且不保护自己免受该值的侵扰会使您的代码不安全。但是,如果您坚持要这样做,则可以选择关闭名为tsconfig.json
https://www.typescriptlang.org/docs/handbook/compiler-options.html
strictNullChecks
如果remoteDb
或db is
为空,您还要尝试查询吗?不仅仅是在运行时破坏代码吗?
编辑:
如果任何一个值为null,该函数将永远不会运行?如果是这种情况,库将错误地键入replicate
和sync
。然后由程序包作者进行监督。
没有任何好的方法可以解决第三方的一个基本错误。记录此问题最简单的方法,但仍要继续键入操作是创建一个带有变量名称的type
来声明推理。也许其他人有更好的主意,但我会这样做:
type POUCH_BD_DATABASE_OR_NULL = PouchDB.Database
export interface DatabaseState {
db: POUCH_BD_DATABASE_OR_NULL;
remoteDb: POUCH_BD_DATABASE_OR_NULL;
dbReplication: PouchDB.Replication.Sync<{}> | null;
dbSyncStatus: number;
dbSyncInfo: string;
dbSyncError: string;
}
EDIT2:
如果您正在{em>之前上对state
进行验证,那么该验证将被传递到startDatabaseSyncronisation
中,那么您为startDatabaseSyncronisation
使用的键入从根本上是不正确的,并且您不能在两个函数之间直接共享interface DatabaseState
。最好的办法是在两个共享元素中分别创建一个interface
,然后在两个界面中创建extend
。
interface DatabaseMetaData {
dbSyncStatus: number;
dbSyncInfo: string;
dbSyncError: string;
}
// for the function where it might be null
export interface DatabaseState extends DatabaseMetaData{
db: PouchDB.Database | null;
remoteDb: PouchDB.Database | null;
dbReplication: PouchDB.Replication.Sync<{}> | null;
}
// for startDatabaseSyncronisation
export interface DatabaseSyncState extends DatabaseMetaData{
db: PouchDB.Database;
remoteDb: PouchDB.Database;
dbReplication: PouchDB.Replication.Sync<{}>;
}
答案 2 :(得分:0)
@elderapo和@Andrew的答案很有用。
@elderapo的答案最直接地回答了我的初始查询,即“为什么打字稿不抱怨函数调用,而抱怨回调?”:
状态值可能会在if check和complate回调之间改变
@Andrew提请注意主要问题,在这种情况下使用null作为有效值可能不安全。
我强烈建议您始终考虑使用null。 null的概念被认为是一个错误,并且不保护自己免受该值的侵害会使您的代码不安全
尽管我不希望db
和remoteDb
的值在分派操作和回调之间恢复为空,但最好完全消除这种可能性。
缺少连接/与数据库的连接丢失由其他代码处理。
我现在不再只是简单地将类型设为null
,而是通过类型转换将它们初始化为空对象。
因此,我不需要禁用strictNullChecks(我想要它们)。
新代码:
export interface DatabaseState {
db: PouchDB.Database;
remoteDb: PouchDB.Database;
dbReplication: PouchDB.Replication.Sync<{}>;
dbSyncStatus: number;
dbSyncInfo: string;
dbSyncError: string;
}
const state: DatabaseState = {
db: {} as PouchDB.Database,
remoteDb: {} as PouchDB.Database,
dbReplication: {} as PouchDB.Replication.Sync<{}>,
dbSyncStatus: SyncStatus.NONE,
dbSyncInfo: "",
dbSyncError: ""
};
async startDatabaseSyncronisation({ state, commit, dispatch }) {
var opts = { live: true, retry: true };
await PouchDB.replicate(state.remoteDb, state.db, opts).on(
"complete",
function(info) {
let replication = PouchDB.sync(state.remoteDb, state.db, opts)
.on("paused", function(err: {}) {
dispatch("onSyncPaused", err);
})
.on("active", function() {
dispatch("onSyncActive");
})
.on("denied", function(err: {}) {
dispatch("onSyncError", err);
})
.on("error", function(err: {}) {
dispatch("onSyncError", err);
})
.on("complete", function() {});
commit(SET_DB_REPLICATION, replication);
}
);
},