我想知道是否有一种通用的方法(也许是一个库)来检查对象的结构(如鸭子键入)。
这对于运行时类型检查和编写单元测试都很有用。
我想我正在寻找与打字稿“ interfaces”类似的东西,bu打字稿仅进行静态检查。
答案 0 :(得分:4)
不是简单的方法,但是实用程序功能呢?:
function isOfType(obj, model) {
for (let prop in model) {
if (!(prop in obj) || typeof obj[prop] !== typeof model[prop] || Array.isArray(model[prop]) !== Array.isArray(obj[prop])) {
return false;
}
if (typeof model[prop] === 'object' && !Array.isArray(model[prop])) {
if (!isOfType(obj[prop], model[prop])) {
return false;
}
}
}
return true;
}
因此,基本上,您可以将任何对象与此模型进行比较。它将确保对象具有模型具有的所有相同类型的属性,并将其递归地应用于嵌套对象。
答案 1 :(得分:1)
即使使用Typescript接口,也无法轻松比较以确保对象的结构与类型匹配。为了进行完整性检查,我使用了条件运算符来检查对象的所有必需属性:
yourObject = {
name: 'cw';
work: {
employed: true;
company: 'stackoverflow'
}
}
if (yourObject &&
yourObject.hasOwnProperty('name') &&
yourObject.hasOwnProperty('work') &&
yourObject.work.hasOwnProperty('employed') &&
yourObject.work.hasOwnProperty('company')
) {
//structure === good
}
答案 2 :(得分:1)
更新:如果您想按https://en.wikipedia.org/wiki/Duck_typing定义鸭子输入,那么您可以使用check-types.js https://gitlab.com/philbooth/check-types.js。请参见check.like(...)。此外,基于Wiki文章,IceMetalPunk的解决方案也成立了。
此外,我还创建了一个代码框:https://codesandbox.io/embed/optimistic-tu-d8hul?expanddevtools=1&fontsize=14&hidenavigation=1
原始答案并非完全正确:“必须给它一个轻声的“否”。无法100%知道对象A在结构上是类X的未修改对象。答案将是一个轻声的“是”。如果您想将A与B进行比较,则可以比较props。同样,尽管您可能遇到A和B都来自同一个父类X且没有被突变的情况。除了调用对象自己的函数外,没有任何外力。”
从MDN借用功能以开始使用。
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Working_with_Objects
function listAllProperties(o) {
var objectToInspect;
var result = [];
for(objectToInspect = o; objectToInspect !== null; objectToInspect = Object.getPrototypeOf(objectToInspect)) {
result = result.concat(Object.getOwnPropertyNames(objectToInspect));
}
return result;
}
此函数将检查我们的对象A是否实际上与从类X创建的基础对象相同。
function isPureObject(baseObj, objToCheck) {
// instanceof to make sure we don't have a object that has the same starting definition but is actually different class
if (!(objToCheck instanceof baseObj.constructor)) return false
let baseProps = listAllProperties(baseObj)
return listAllProperties(objToCheck).every(prop => baseProps.indexOf(prop) > -1)
}
现在让我们创建几个测试类。
class Test {
constructor(b) { this.b = b }
a() { this.d = 18}
c = 5
}
// this is effective the same as Test but is a different class
class LikeTest {
constructor(b) { this.b = b }
a() { this.d = 18 }
c = 5
}
创建一些新的测试对象
let a = new Test(3)
let b = new Test(42)
let c = new Test(42)
let likeTest = new LikeTest(3)
c.z = 10
let base = new Test(0)
对于我们的第一组测试,我们将展示我们的函数“ isPureObject”可以正确地测试A是X类的对象,并且没有在起始模板之外进行突变。我还包括IceMetalPunk的函数isOfType和check.like进行比较。
测试基本情况,即测试对象“是”没有被突变的鸭子。
console.log(`Test basic cases where the test object "is" a duck that has not been mutated.`);
console.log(`------------------------------------------------------------`);
console.log(`expect true - isPureObject(base, a) = ${isPureObject(base, a)}`);
console.log(`expect true - isOfType(a, base) = ${isOfType(a, base)}`);
console.log(`expect true - check.like(a, base) = ${check.like(a, base)}`);
console.log(`expect true - isPureObject(base, b) = ${isPureObject(base, b)}`);
console.log(`expect true - isOfType(b, base) = ${isOfType(b, base)}`);
console.log(`expect true - check.like(b, base) = ${check.like(b, base)}`);
测试用例,其中测试对象“是”一只突变鸭。
console.log(`\n\nTest cases where the test object "is" a mutated duck.`);
console.log(`------------------------------------------------------------`);
console.log(`expect false - isPureObject(base, c) = ${isPureObject(base, c)}`);
console.log(`expect true - isOfType(c, base) = ${isOfType(c, base)}`);
console.log(`expect true - check.like(c, base) = ${check.like(c, base)}`);
测试用例,其中测试对象“像”鸭子,而不是鸭子。
console.log(`\n\nTest cases where the test object "is like" a duck but not a duck.`);
console.log(`------------------------------------------------------------`);
console.log(`expect false - isPureObject(base, likeTest) = ${isPureObject(base,likeTest)}`);
console.log(`expect true - isOfType(likeTest, base) = ${isOfType(likeTest, base)}`);
console.log(`expect true - check.like(likeTest, base) = ${check.like(likeTest, base)}`);
最后,我们通过使被测对象以预期的方式发生变异并使isPureObject函数失败来说明为什么这是一个如此棘手的问题。
a.a();
console.log('\n\nCalled a.a() which sets this.d to a value that was not previously defined.')
console.log(`------------------------------------------------------------`);
console.log(`expect true - isPureObject(base, a) after calling a.a() = ${isPureObject(base, a)}`)
console.log(`expect true - isOfType(a, base) after calling a.a() = ${isOfType(a, base)}`)
console.log(`expect true - check.like(a, base) after calling a.a() = ${check.like(a, base)}`)
原始答案:“同样,我不能对此进行强硬的否定,因为我怀疑可以使用object.constructor.toSting()与对象的当前状态进行比较来做到这一点,甚至这可能还不够。我还知道React.js可以按照这些原则做一些事情,但是它们可能针对非常特定的对象/类来做,而我假设您正在寻找一个广泛的通用用例。”
已更新:确实取决于您要执行的操作。如果您正在寻找鸭子的类型,那么有很多解决方案。这里已经涵盖了一些。如果您正在寻找结构/未突变的对象,则isPureObject将处理该对象。但是,它将无法自动变异的对象。